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.tsfrom earlier Y.Map string fields. - Workspace notes — a separate
notessub-doc backed by thecomponents/notes/Editor.svelterich-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.ts—node.updateandselection.updatecarry 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.