Skip to content

local-first: migrate manuscript text to Y.Text and gate the source-of-truth flip #555

Description

@qnbs

Context

ROADMAP.md explicitly lists the next Local-First phases from ADR-0008 as:

B2.1 — migrate manuscript text to Y.Text
B2.2 — flip the source of truth behind enableLocalFirstSync

The repository already has Yjs/Local-First infrastructure and observation/shadow behavior, but there is no durable issue that owns this later text-authority migration. Issue #548 is intentionally much narrower: it tracks prototype-named entity IDs in the existing Yjs reconstruction path and must not become the umbrella for B2.

Goal

Move manuscript text toward Y.Text in a staged, reversible, evidence-driven way, then permit a source-of-truth switch only after deterministic parity and recovery gates pass.

The migration must preserve current user data and editing semantics. It must not treat “Yjs exists in the repository” as proof that Yjs is already safe to become authoritative for manuscript text.

Phase B2.1 — Y.Text migration proof

Define the smallest renderer-neutral manuscript-text representation and adapter boundary required to mirror current authoritative editor/project state into Y.Text.

Prove at minimum:

  • exact text content round-trips without normalization drift;
  • section/document identity remains stable;
  • ordering and structural metadata remain intact;
  • Unicode/grapheme/line-ending behavior is deterministic;
  • edits applied through current editor transactions produce the expected Y.Text state;
  • Yjs updates can reconstruct the same current project state without dropping unknown/unmodeled project fields;
  • project switching cannot apply stale updates to another project;
  • teardown/reopen/restart does not leak observers or duplicate updates;
  • large manuscript behavior remains bounded and editor responsiveness is protected.

During B2.1 the current project state remains authoritative unless an explicitly admitted narrower vertical slice says otherwise.

Phase B2.2 — source-of-truth admission

Do not flip enableLocalFirstSync into production authority merely because shadow parity is green in a few unit fixtures.

Required admission gates include:

NO-LOSS ROUND TRIP
DETERMINISTIC CURRENT↔Y.TEXT PARITY
UNDO/REDO SEMANTICS DEFINED
PROJECT-SWITCH STALE-UPDATE PROTECTION
PERSISTENCE/RESTART RECOVERY
OFFLINE BEHAVIOR
MULTI-WINDOW/TAB AUTHORITY WHERE APPLICABLE
ROLLBACK/FALLBACK PATH
OBSERVABILITY WITHOUT MANUSCRIPT LEAKAGE

The switch must be reversible during rollout. Persisted data written by the new authority must not strand users who fall back to the previous application version/path unless that compatibility break is explicitly versioned and migrated.

Undo/history contract

Before authority changes, reconcile:

  • current Redux/project undo semantics;
  • Yjs transaction origins;
  • local undo manager behavior if used;
  • editor command grouping;
  • startup repair/migration transactions;
  • remote/collaborative update behavior.

Do not silently create two independent undo histories that both appear authoritative.

Persistence and recovery

Define exactly what is persisted and where for the admitted phase:

  • canonical project snapshot/state;
  • Yjs update log/state vector if retained;
  • compaction/checkpoint behavior;
  • corruption/incomplete-write recovery;
  • migration from existing projects;
  • rollback after interrupted migration.

Coordinate browser writer/concurrency semantics with #480 where the PWA actually has multiple tabs/windows. Do not make #480 the generic Local-First text-architecture owner.

Relationship to collaboration

Yjs-based real-time collaboration and Local-First manuscript authority overlap technically but are not the same product contract.

Do not fold invite-link UX (#349) or unrelated collaboration features into this migration. Shared CRDT primitives may be reused, but authority, persistence and recovery acceptance must be explicit for Local-First text.

Relationship to current issues

Regression/evidence matrix

At minimum cover:

  • empty manuscript;
  • single and many sections;
  • very large text;
  • Unicode/RTL/emoji/graphemes;
  • rapid edit bursts;
  • undo/redo grouping;
  • project switch during pending update;
  • app reload/restart;
  • interrupted persistence/compaction;
  • offline edit and resume;
  • two active views where the platform permits it;
  • old/current persisted project migration;
  • rollback from shadow/new-authority mode;
  • malformed/foreign Yjs state failing safely rather than replacing valid project data.

Acceptance criteria

  • B2.1 has an explicit adapter/ownership contract and remains non-authoritative until its gates pass.
  • Manuscript text round-trips through Y.Text without semantic/data loss.
  • Current editor transactions, project switching and undo semantics have deterministic parity evidence.
  • Persistence/restart/interruption recovery is defined and tested.
  • No stale update can apply to the wrong project.
  • Multi-tab/window authority is reconciled where applicable.
  • B2.2 source-of-truth switch has a reversible rollout and explicit rollback path.
  • No competing Redux/Yjs authority can silently overwrite the other.
  • Representative historical/current projects migrate without losing unknown or still-supported data.
  • ROADMAP.md / ADR-0008 status is updated only when the actual admission state changes.

Non-goals

  • rewriting the entire project domain around Yjs in one PR;
  • implementing collaboration invite UX;
  • making Local-First synonymous with cloud sync;
  • starting a source-of-truth flip before shadow/evidence gates pass;
  • moving AI services into Rust;
  • coupling the migration to Qt implementation timing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions