Collaborative prose as Y.Text — and what stays Y.Map

CareerVector's collaboration model assumes more than one author per field at any moment. A friend rephrases a bullet while the user keeps typing the next one; a mentor edits the summary while an agent rewrites it for one specific job. The data model must merge those edits without one party silently clobbering the other.

The rule

Default for any new human-editable text field: Y.Text.

Use Y.Text for Use Y.Map scalar for
Bullets, headings Job title, company, location
Summaries, narrative paragraphs Salary, status, score
Workspace notes Format settings, locale codes
Cover-letter body Phase / kanban column id
Recipient text Custom-column boolean / numeric value

The litmus test: if there is one right answer at any moment and humans treat the field as a fact, last-write-wins on Y.Map is correct. If two people might be improving the same wording, character-level CRDT merge on Y.Text is correct.

This rule is the reason the "single author privately editing their resume" mental model is wrong for CareerVector. The product premise is multi-author collaboration, so the data model defaults to multi-author safe. See PRINCIPLES.md §6.

Where Y.Text already lives

  • CVL node content (bullets, headings, summaries, body paragraphs) inside the recursive Node tree. Migrated by ui/scripts/migrate-prose-to-ytext.ts from earlier Y.Map string fields.
  • Workspace notes — a separate notes sub-doc backed by the components/notes/Editor.svelte rich-text surface.
  • Tailored snapshot content. The snapshot is taken as a structural copy of the quarry tree; OPEN-tier prose written into the snapshot remains Y.Text so per-job edits can still merge cleanly between collaborators.

Collaborative notes

The notes editor is its own sub-doc rather than a single Y.Text field inside settings because notes can grow large, are written far more often than settings, and benefit from their own edge-cache lane. Headings and inline marks are encoded into the Y.Text via the notes/markdown.ts adapter so the rendered output stays markdown-shaped without each formatting gesture needing a structural op.

What never becomes Y.Text

  • Anything in the FIXED tier of the quarry. Identity fields, education rows, employer dates, salutation formalities. They are stored as Y.Map scalars and never sent to the LLM — collaboration on these is "change the typed fact", not "merge two phrasings".
  • Score values, evaluation booleans, custom-column numerics. These are outputs, not co-authored prose.

Implementation seams

  • lib/mutations/src/opsCatalog.tsnode.update and selection.update carry deltas that target either Y.Text content or Y.Map scalar fields, routed by the target field's runtime type.
  • lib/workspace-client/ — the applier knows how to translate Y.Text inserts/deletes into the same broker bytes peers already receive for Y.Map writes.
  • ui/src/lib/cvl/yext-binding.ts — binds an editor surface to a Y.Text inside a Node, so the existing CVL editor components do not need to know about CRDT details.
Source: wiki/content/canon/cv-collaborative-prose.md