Work together on documents in real time — comment on passages, edit freely, and, whenever you want to know what changed, open Versions, name the two versions you care about, and read the whole thing as a redline (who, when, what) with a one-click revert.
How It Works: Annotations as Satellite Entities
*The document text stays clean. Comments capture the character range they cover; tracked changes are computed from the version history. Both are recomputed at render time.*MeshWeaver keeps the document's markdown clean — nothing is woven into it. The two annotation kinds get there differently, and the difference is the point:
| Annotation type | Where it lives | Source of truth |
|---|---|---|
| Comment | _Comment satellite |
The satellite (genuinely additional data — the document never carried it) |
| Tracked change | nowhere — a view model | The node's version history (IVersionQuery / mesh_node_history) |
A comment records, on its satellite, the character range it covers (Start/Length), the document version that range was captured against, and the document text at that version (the anchor).
A tracked change stores nothing at all. The version history is already the authoritative record of every change — who made it, when, and the full text before and after — so ChangeProjection diffs a baseline version against the current text and attributes each resulting hunk to the version step that introduced it. Persisting that a second time only bought a failure class: anchors going stale as the document moved, orphaned satellite state, and two answers to "what changed".
Legacy
_Trackingsatellites. Older builds persisted tracked changes at{doc}/_Tracking/{id}. Nothing writes them any more; the node type and the_Tracking → annotationstable mapping stay registered for a deprecation window so existing rows remain readable.
Capturing and recomputing positions
There is no "strip markers / reassemble" round-trip and no marker is ever written into the source. Instead:
- Capture — when you comment, the satellite records
Start,Length,Version, andAnchorText(the clean document text at that version) plus the highlighted text. A tracked change captures nothing: it is projected from the history, and the text it was projected against becomes its anchor. - Recompute — when the document is displayed, each annotation's effective range is computed against the current text. If the document is still at the captured version, the stored offsets are used directly; if it has moved on, the engine diffs the anchor text against the current text and maps the offsets through that diff (a
diff_xIndex-style position map). This is exposed asEffectiveStart/EffectiveEnd/EffectiveVersion. - Overlay — the comment highlight, or the tracked-change diff, is injected as a transient span for that render only.
Because the range is recomputed from the actual edit delta, an annotation follows its text when content is inserted or deleted above it — without the document ever carrying annotation state.
Annotation entity reference
Comment (_Comment partition)
| Field | Purpose |
|---|---|
Start / Length |
The captured character range in the document's clean text |
Version / AnchorText |
The document version + text the range was captured against |
EffectiveStart / EffectiveEnd |
The range recomputed for the current text (not persisted) |
HighlightedText |
The originally selected text |
Status |
Active or Resolved |
PrimaryNodePath |
Document path used for permission delegation |
TrackedChange — a view model, computed by ChangeProjection, never persisted
| Field | Purpose |
|---|---|
ChangeType |
Insertion, Deletion, or Replacement — classified from the diff hunk |
Author / CreatedAt / Version |
The version-history step that introduced the hunk |
OriginalText / NewText |
What the range held before, and what it holds now |
Start / Length / AnchorText |
The range in the text it was projected against (so a later edit re-locates it) |
PrimaryNodePath |
The document the change belongs to |
Comment has IsSatelliteType = true; TrackedChange has no node type of its own any more (the legacy one stays registered read-only — see above).
Adding Comments
Select any passage and click Comment. A Comment satellite is created that captures the selected range, the document version, and the anchor text — the document itself is untouched, so commenting works even without edit access. The highlight is rendered inline from the satellite.
Comments without a selected range attach to the bottom of the page.
Example — a paragraph with comments
MeshWeaver is a powerful platform for building collaborative applications. It provides real-time synchronization and conflict-free editing.
A reviewer might attach comments to:
- "powerful platform" — flag for more specific metrics
- "collaborative applications" — request examples
- "conflict-free editing" — ask about the underlying technology
Making Suggestions (Track Changes)
Suggest Edit (in the UI, or the agent tool of the same name) applies the edit to the document as a normal versioned write. There is no pending-proposal limbo: the edit lands and the version history records who made it and when. Open Versions and the edit reads as a tracked change with a one-click Revert. Reverting is itself a versioned write, so the whole review is auditable instead of a satellite quietly appearing and disappearing.
The redline is never on by default. Reading a document is not reviewing it: the document page shows the document, comments and all, and nothing else. The redline appears only where a reader has said which two versions they want compared — see Choosing what to compare below. That is also why there is no "show changes" toggle to hunt for: the comparison IS the switch.
Additions
New text shows as a green-underlined insertion in the redline.
The quarterly report shows significant growth of 25% in user engagement.
Deletions
Removed text shows struck through, reconstructed from the baseline version — the current document does not carry it.
Please review the outdated documentation before the meeting.
Combined example
Our team has completed the comprehensive analysis of the market trends. We recommend immediate action on the following priorities:
- Expand into European markets
- Reallocate marketing spend to digital channels
- Improve customer retention rates
Choosing what to compare
Open Versions. The list of versions IS the picker — there is no separate dialog to fill in and no baseline to remember between clicks:
| You want | Do this |
|---|---|
| What has happened since some version | Compare with current on that version's row — one click |
| What changed between two specific versions | From on the older, To on the newer, then Compare |
| To start over | Clear selection |
A comparison needs two endpoints, so Compare stays inert until both are named — and says so rather than failing quietly when clicked. Claiming an endpoint that would invert the pair (a From at or after the current To) releases the other one instead of offering a backwards comparison: the picker cannot be driven into a state that Compare would have to refuse.
Compare with current is on every row except the current version's, where it would compare a version with itself.
What the comparison shows
Prose renders as the redline: every hunk introduced between the two versions marked up inline — insertions underlined, deletions struck through — with a card per change naming the author and the time, read straight off the version that introduced it. Non-prose content (and prose, via Show the source diff) renders as the side-by-side source diff instead, which is what you want for front matter or link syntax.
Comparing against the current document keeps the view live: further edits appear as they land, and each change can be reverted. Comparing two historical versions pins the view to the document as it stood at the target version — there is nothing on screen to revert INTO, so revert is not offered there.
Reviewing Changes
Keeping a change
Do nothing. The change is already in the document — that is precisely why it appears in the version history and therefore in the redline. There is no "accept" button because there is nothing left to apply.
Reverting a change
Click ↩ on the change card. The range is re-resolved against the live document (so a concurrent edit can never make the revert splice the wrong text) and the previous text is put back:
- Revert an insertion — the added text is removed again.
- Revert a deletion — the removed text comes back.
- Revert a replacement — the old text is restored.
The revert is a normal versioned write, so it shows up in the history exactly like the edit it undoes.
Reverting everything
Use the Versions page: pick the version you want and restore it. That is one write with one clear meaning, instead of N independent reverts racing each other.
Position Tracking Under Edits
When the document is edited above or around an annotation, its highlight follows the text — without any stored position drifting, because positions are recomputed from the edit delta:
- Each annotation captured
Start/Lengthagainst a knownVersionandAnchorText. - At display, if the document has advanced past that version, the engine diffs
AnchorTextagainst the current text. - Offsets before an edit map unchanged; offsets after shift by the net length delta; an edit inside the range grows or shrinks it; if the anchored text is gone the annotation is dropped from the inline view.
- The result is the
EffectiveStart/EffectiveEndused for that render.
This is a pure, deterministic text operation — the same engine drives both comment highlights and the tracked-change diff, and it is covered by an extensive unit-test suite.
Working with Multiple Collaborators
Multiple editors work on the same document without conflicts:
- Each change card names the author and when — read straight off the version that introduced it.
- Comments show the author name and timestamp.
- Comment satellites and the derived change list update reactively for every connected editor.
An edit whose text several people touched attributes to nobody rather than to the wrong person — the card then reads as an unattributed change. That is deliberate: guessing an author is worse than admitting the edit is shared.
Example — team review session
Project Proposal (3 collaborators editing)
The proposed timeline for Phase 1 is 4 months. This aggressive but achievable schedule requires:
- Additional resources from the engineering team
- Daily standup meetings
- A dedicated project manager
Tips for Effective Collaboration
- Comment before you change — if you are uncertain, ask rather than edit.
- Keep edits atomic — one logical change per write makes both the redline and the revert clean.
- Resolve threads when done — mark comment threads resolved to keep the sidebar clean.
- Reach for Versions for a wholesale undo — restoring a version beats reverting a dozen cards.
- Add context — a comment explaining why you made a change helps reviewers decide quickly.