This plan breaks Wonky Write into workstreams (WS-W*) that different engineers or coding agents can build in parallel with minimal interference. It aligns with the suite roadmap ../14-roadmap.md (milestones M0–M7, suite workstreams WS-0…WS-13) and the quality spec ../11-quality-testing-accessibility.md.
Specs per workstream: model 02, sync 03, editor 04, screens 05, themes 06, import/export/print 07, collaboration 08, MCP & AI 09.
- Contract first. Each workstream starts by committing its public Dart interfaces, Serverpod model YAMLs and endpoint signatures with stub/fake implementations (§4). Dependents code against the interfaces and fakes from day one; real implementations replace stubs without API changes.
- Ownership by folder. Each workstream owns specific folders (§3). Edits outside one's folders are limited to additive registrations (§5).
- Pure core first. Anything that can be pure Dart (
wonky_write_core) is built and tested there before UI work depends on it — it's the cheapest code to test and is shared by client, server, MCP and AI. - Vertical slices per milestone. Every milestone ends with a demo on web and macOS through the critical journeys of 11 §1.1.
- Tests are part of the contract. Interfaces ship with a conformance test suite that every implementation (fake and real) must pass.
| Suite milestone | Write scope | Exit criteria (Write) |
|---|---|---|
| M0 · Foundations | Package scaffolds (packages/wonky_write_core; the wonky_write app joins the workspace and runs on wonky_app, served at /write/), contract stubs for W1–W5 (§4), vendored super_editor in third_party/ (suite 01 §2.3), dependency-rule CI, Write test infra skeleton (WS-W0), spikes S1–S3 (§8). |
wonky_write_core builds on VM + web; editor screen shows a hard-coded Delta via the mapper stub; spikes reported. |
| M1 · Shell & Drive | Write app config in the shell (routes /d/:uuid…, home filtered to documents), DriveEndpoint.createDocument with Document row, empty editor route with title field, Write settings page stub. |
Create/open/rename/trash documents from the Write home. |
| M2 · Write MVP | W1 (schema, validator, normalizer, Markdown codec, IR), W2 (OT server), W3 (mapper, applier, extractor, core editing behaviours of 04), W4 (sync client + offline outbox), W5 (undo), W6 core chrome (menubar, toolbar, status bar, outline, find/replace, word count), W7-lite (Wonky Default theme through WriteStylesheetBuilder, fonts pipeline), W8-lite (Markdown/TXT/HTML import, Markdown/TXT export, page setup model + Pages/Pageless rendering), W11-lite (write.get_document, write.insert_markdown for journey 8 smoke). |
Journeys 1–3 (Write parts); OT fuzzer, undo fuzzer, mapper/applier property tests green; keystroke budget met on 100 pages. |
| M3 · Sheets MVP | (Write) hardening: perf, IME QA on Windows/Linux, bug fixes; W13 images (upload, offline queue) and mentions. | No P0 Write bugs open; perf budgets green in CI. |
| M4 · Collaboration | W9 (comment anchors, margin, suggestions, accept/reject, decisions), W10 (history diff/restore, presence cursors, follow, agent presence). | Journeys 2, 5, 6; OT fuzzer including overlays green. |
| M5 · Depth | W7 full (theme model, 8 built-ins, theme editor, contrast checker, all component builders), W8 full (pagination engine, PDF, HTML, DOCX, ODT, RTF, EPUB, DOCX/ODT/RTF import, print preview, export endpoint), W13 tables editor, W6 remaining dialogs (page setup, export, document properties). | Journeys 7, 9; export validator CI green; theme goldens green. |
| M6 · Agents & Automation | W11 full (write.* tools, ui.write.*, resources, prompts), W12 (assistant tool binding, inline rewrite, continue, summarize/outline/proofread, AI undo grouping). |
Journeys 8, 10 (Write parts); MCP integration suite green. |
| M7 · Polish & Scale | A11y audit (editor semantics, announcements), i18n (pseudo-locales, RTL documents), deferred loading (exporters, theme editor, AI), large-doc perf (2M chars), spellcheck (P1), P1 backlog. | Budgets in 11 §2 met; a11y checklist complete. |
Each entry: scope · owned folders · provides · depends on · deliverables · acceptance tests · milestone. "Depends on" refers to interfaces (available from M0/M2 week 1 as stubs), not to finished implementations, unless marked (impl).
- Scope: random valid Delta generator, random edit generator (text/format/block/embed/
overlay ops), in-process multi-client OT simulator (
WriteSimulatorwith network delay/reorder/ disconnect), document corpus (wonky_write/test_corpus/: Markdown, HTML from Google Docs/Word, DOCX/ODT/RTF fixtures, 100-page perf doc, Unicode/RTL/emoji doc), golden helpers (font loading for tests, PDF rasterization viapdftoppm), CI validator image (LibreOffice, epubcheck, Nu checker, ODF validator, poppler). - Owns:
wonky_write_core/test/support/,wonky_write/test_corpus/,tool/write_ci/. - Provides:
DeltaGen,EditGen,WriteSimulator,CorpusLoader,GoldenPdf. - Depends on: W1 interfaces. Milestone: M0 → ongoing.
- Scope: Wonky Delta Schema v1 types,
WonkyDeltaValidator,WonkyDeltaNormalizer, canonical JSON + SHA-256 hashing,MarkdownCodec(import/export, front matter, escaping),DocTreeIR (DocTreeBuilder,DocTreeToDelta), derived data (outline, stats, plain text),AddressResolver(quote/heading/offset) andDocumentEditsop builders (insert Markdown, replace range with minimal diff, format, block type, tables) shared by commands, MCP and AI. - Owns:
wonky_write_core/lib/{delta,markdown,ir,derived,edit}/. - Provides: interfaces in §4.1. Depends on:
wonky_core(WS-1). - Deliverables: all of 02 §1–§2, §5; 07 §2.1; 09 §7
edit/. - Acceptance: Markdown round-trip property test (10k docs), validator/normalizer idempotence
(
normalize(normalize(d)) == normalize(d)),DocumentEditsresults always validate, address resolver Unicode tests. Milestone: M0 (contracts) → M2.
- Scope: Serverpod models (
Document,DocumentOp,DocumentSnapshot,DocumentMetaChange),DocumentEndpoint(stream + helpers),OtService(lock, transform, normalize, validate, persist, broadcast),DocumentSessionManager(in-memory cache, Redis fan-out), snapshots, integrity hashes, permission-restricted op validation incl. suggestion shapes (08 §2.10),OverlayIndexhook points,updateMeta, op-log pruning job,HeadlessDocumentEditor(server-side OT client used by W11/W12/W10). - Owns:
wonky_server/lib/src/write/{models,ot,endpoints/document_endpoint.dart,services/document_service.dart}. - Provides: endpoint signatures (03 §1),
OtService.submit,HeadlessDocumentEditor(§4.2). Depends on: W1 (impl for validation), WS-6AccessService. - Acceptance:
serverpod_testsuites for every message type; OT convergence fuzzer against the real endpoint (in-process); idempotent resubmission;rebaseTooOld; ≤ 20 ms p95 op processing at 50 editors. Milestone: M2 (suggestion validation M4).
- Scope:
DeltaDocumentMapper,DeltaIndex(Fenwick tree),DeltaApplier(non-historical edits, caret preservation, IME resync),ChangeDeltaExtractor(event mapping + line-diff fallback, debug invariant), custom attributions (CommentAttribution,SuggestionAttribution,MentionAttribution), editor widget composition, request handler chain (mode guard, schema guard, suggestion rewrite hook), keyboard actions, clipboard, Markdown autoformat, editing behaviours of 04, layers framework (highlights, remote cursors, ghost text slots), Pages/Pageless frame and approximate pagination (04 §29). - Owns:
wonky_write/lib/features/editor/,third_party/super_editor/(patches SE-1…SE-5, 04 §2.2; upstream PRs where possible). - Provides:
WriteDocumentSessionfaçade implementation (§4.3),EditorLayerRegistry. - Depends on: W1, W4 interface, W7
WriteStylesheetBuilderinterface. - Acceptance: mapper round trip (random deltas), applier property test (
composeequivalence + selection =transformPosition), IME integration tests (web + macOS), all 04 ACs. Milestone: M2 (P1 behaviours M5/M7).
- Scope:
DocumentSyncController(ot.js state machine, transforms of selection/undo/overlay ranges), stream supervision/reconnect, gap fill, integrity check, local SQLite tables (LocalDocument,LocalPendingOp,LocalUndoStack,LocalTheme), outbox composition, offline document creation, "save offline changes as copy" (rebaseTooOld), sync status. - Owns:
wonky_write/lib/features/sync/,…/data/local_store/. - Provides:
DocumentSyncControllerinterface (§4.3),WriteLocalStore. - Depends on: W2 endpoint signatures (generated client), W1.
- Acceptance: simulator tests with the real controller vs. in-process server; kill/restart app mid-outbox → no loss; offline 1 h of edits rebases. Milestone: M2.
- Scope:
WriteUndoHandler(write.content: inverse deltas, grouping/coalescing, selection snapshots, rebase through remote ops),write.metahandler, persistence, MCP/AI step labelling, AI run grouping (onBehalfOfSessionId, 09 §5.2). - Owns:
wonky_write/lib/features/undo/. - Depends on: suite
UndoService(WS-3), W4 (transform hook). - Acceptance: undo fuzzer (random local+remote ops; undo-all ⇒ initial + remote only), every command execute→undo→redo test passes via the shared harness. Milestone: M2.
- Scope: editor screen layout (title row,
WonkyMenubarfromMenuSpec,WonkyToolbar, status bar), command catalog registration for 04/05 commands, context menus, floating toolbar, slash menu, panels (outline, find & replace, word count), dialogs (link, special characters, document properties, page setup UI shell, export dialog shell), mode switcher, responsive behaviour, light/dark,WonkyDialogSpecusage for MCP. - Owns:
wonky_write/lib/{config,features/{chrome,outline,find_replace,word_count,dialogs}}/,lib/commands/{format,insert,view,edit}_commands.dart. - Depends on: suite shell (WS-3), W3 façade, command contracts of other workstreams (menu items reference command ids only).
- Acceptance: 05 ACs, widget tests for every menu/toolbar item state,
ui.get_menu_treesnapshot. Milestone: M2 (core) → M5.
- Scope: theme model/schema/validator/migrations, resolver, dark derivation (OKLCH), contrast
checker, 8 built-ins, font registry + sync tool +
FontProviders,WriteStylesheetBuilder, inline styler, themed component builders, layers (chips, highlights),WriteThemeserver models +WriteThemeEndpoint+ broadcast,ThemeRepository/cache, theme editor route, theme commands, theme MCP tools. - Owns:
wonky_write_core/lib/{theme,fonts,highlight}/,wonky_write/lib/features/{theme,theme_editor}/,wonky_server/lib/src/write/{models/write_theme*,endpoints/write_theme_endpoint.dart,mcp/theme_tools.dart},wonky_write/fonts/. - Provides:
ThemeResolver,ResolvedWriteTheme,WriteStylesheetBuilder,FontProvider, CSS/PDF/DOCX/ODT/RTF style mappers (consumed by W8). - Depends on: W3 (component builder hooks), suite design-system widgets (
FontPicker,WonkyColorPicker,WonkyNumberStepper). - Acceptance: 06 §14. Milestone: M2-lite (Wonky Default, fonts, builder) → M5.
- Scope: importers (MD/TXT/HTML in M2; DOCX M5; ODT/RTF P2), exporters (MD/TXT in M2;
PDF/HTML/DOCX/ODT/RTF/EPUB M5), pagination engine +
WonkyParagraph, page setup model + validator + dialog, print preview route,WriteExportEndpoint,DriveEndpoint.importWrite pipeline, image resolvers, SSRF-safe fetcher, deterministic zip writer, export commands & download submenu. - Owns:
wonky_write_core/lib/{import,export,layout}/,wonky_write/lib/features/{export,print,page_setup}/,wonky_server/lib/src/write/{endpoints/write_export_endpoint.dart,imports/}. - Depends on: W1 (IR), W7 (style mappers, fonts), suite files service (WS-12).
- Acceptance: 07 §13; validator CI. Milestone: M2-lite → M5.
- Scope: comment anchor creation/deletion/re-attach, pending composer ranges, margin layout
- markers mode, highlight layers,
OverlayIndextransitions (orphan/un-orphan, suggestion threads, decision inference, notifications),SuggestionRewriter+ editor reaction,SuggestionOps,SuggestionView, suggestion cards, accept/reject all, suggestion commands.
- markers mode, highlight layers,
- Owns:
wonky_write_core/lib/collab/{overlay_index,suggestion_*}.dart,wonky_write/lib/features/{comments,suggestions}/,wonky_server/lib/src/write/collab/. - Depends on: W2 (op hooks), W3 (layers, reaction hook), suite comments framework (WS-8).
- Acceptance: 08 §11–§12 (comments/suggestions parts). Milestone: M4.
- Scope:
WriteVersionProvider(capture/materialize),AttributedDiff, diff cache,WriteHistoryEndpoint, history route (diff rendering, legend, change navigation, compare), client restore flow,versions.*Write behaviour,write.compare_versions; remote cursor/selection layers, follow mode, agent presence, activity summaries. - Owns:
wonky_write_core/lib/collab/attributed_diff.dart,wonky_server/lib/src/write/versions/,wonky_write/lib/features/{history,presence}/. - Depends on: W2, W3, suite versions framework (WS-9), presence (WS-7).
- Acceptance: 08 §11–§12 (history/presence parts). Milestone: M4.
- Scope:
write.*tool definitions inwonky_core/lib/mcp/write_tools.dart, headless tool implementations overHeadlessDocumentEditor,HeadlessChange+changes.revertfor Write, resources/prompts,ui.write.*bridge tools, tool descriptions, integration tests. - Owns:
wonky_core/lib/mcp/write_tools.dart,wonky_server/lib/src/write/mcp/,wonky_write/lib/mcp/. - Depends on: W1 (
DocumentEdits,AddressResolver), W2 (HeadlessDocumentEditor), suite MCP platform (WS-10), W9/W10 for suggestion/version tools. - Acceptance: 09 §8–§9. Milestone: M2-lite → M6.
- Scope:
WriteContextBuilder, Write prompts, assistant tool binding/allowlist, destructive guard, inline rewrite service + endpoint method, preview overlay, ghost text, continue writing, summarize/outline, proofread (report_issues), AI commands, undo grouping client side. - Owns:
wonky_server/lib/src/write/ai/,wonky_write/lib/features/ai/,lib/commands/ai_commands.dart. - Depends on: W11 (tools), suite AI platform (WS-11), W3 layers, W9 (
SuggestionRewriterfor Suggest apply mode). - Acceptance: 09 §8–§9 (AI parts). Milestone: M6.
- Scope: image insert/upload (button, paste, drop, URL), offline upload queue, placeholder
nodes, image component (with W7 styling), table insertion + table editor (04), mention
autocomplete + chip,
wonky-file://resolution and caching. - Owns:
wonky_write/lib/features/{images,tables,mentions}/. - Depends on: W3, suite files (WS-12), user search (WS-4).
- Acceptance: corresponding 04 ACs. Milestone: M3 (images, mentions) → M5 (tables).
All contracts live where their owner works; fakes live in …/testing/ libraries exported
for other workstreams' tests.
// delta/
abstract interface class WonkyDeltaValidator { ValidationResult validate(Delta doc); }
abstract interface class WonkyDeltaNormalizer { NormalizeResult normalize(Delta doc); } // doc + fix-up change
String canonicalJson(Delta doc); String documentHash(Delta doc);
// markdown/
abstract interface class MarkdownCodec {
ImportResult importMarkdown(String markdown);
String exportMarkdown(Delta doc, {SuggestionView view = SuggestionView.accepted, ImageLinkMode images});
}
// ir/
abstract interface class DocTreeBuilder { DocTree fromDelta(Delta doc, {SuggestionView view}); }
abstract interface class DocTreeToDelta { Delta convert(DocTree tree); }
// derived/
abstract interface class OutlineExtractor { List<OutlineEntry> outline(Delta doc); }
abstract interface class DocumentStatsCalculator { DocumentStats stats(Delta doc, {TextRange? range}); }
// edit/
abstract interface class AddressResolver {
ResolvedRange resolveRange(Delta doc, RangeAddress address); // throws AddressException(code, details)
int resolvePosition(Delta doc, PositionAddress address);
}
abstract interface class DocumentEdits { // pure op builders → change Delta
Delta insertMarkdown(Delta doc, int at, String markdown, {InsertAs as});
Delta replaceRange(Delta doc, ResolvedRange range, Delta fragment, {bool preserveOverlays = true});
Delta deleteRange(Delta doc, ResolvedRange range);
Delta applyInlineFormat(Delta doc, ResolvedRange range, InlineFormatPatch patch);
Delta setBlockType(Delta doc, ResolvedRange range, BlockTypeSpec spec);
Delta replaceText(Delta doc, FindSpec find, String replacement, Occurrence which);
Delta updateTable(Delta doc, String tableId, List<TableOperation> ops);
}
// theme/ (W7), layout/ import/ export/ (W8), collab/ (W9, W10) — see 06 §3, 07 §2.2, §7, 08 §2.3, §4.2
abstract interface class ThemeResolver { ResolvedWriteTheme resolve(WriteThemeData t, ThemeVariant v); }
abstract interface class PaginationEngine { PaginationResult paginate(List<BlockMetrics> blocks, PageGeometry g); }
abstract interface class SuggestionRewriter { Delta rewrite(Delta docBefore, Delta change, SuggestionContext ctx); }
abstract interface class SuggestionOps {
Delta accept(Delta doc, Set<String> suggestionIds);
Delta reject(Delta doc, Set<String> suggestionIds);
}
abstract interface class OverlayIndex {
void reset(Delta doc);
List<OverlayTransition> apply(Delta op, Delta inverse); // 0→>0 / >0→0 per key
}
abstract interface class AttributedDiff {
WriteDiff diff(Delta docA, List<AuthoredOp> ops); // exact
WriteDiff diffSnapshots(Delta docA, Delta docB); // fallback
}- Model YAMLs: 02 §3, 06 §5.1, 08 §4.2 (
write_diff_cache), 09 §1.4 (headless_change). - Endpoint signatures (stub bodies throwing
UnimplementedError, generated client available to clients immediately):DocumentEndpoint,WriteThemeEndpoint,WriteExportEndpoint,WriteHistoryEndpoint,AssistantEndpoint.inlineRewrite. - Service contracts:
abstract interface class OtService {
Future<SubmitResult> submit(Session s, DocumentRef doc, SubmitRequest req); // used by stream + headless
Future<Delta> head(Session s, DocumentRef doc); // cached
Stream<AppliedOp> watch(DocumentRef doc); // for OverlayIndex, presence, MCP resources
}
abstract interface class HeadlessDocumentEditor {
Future<HeadlessResult> edit(Session s, DocumentRef doc, HeadlessEditRequest req);
// req: build(Delta head) → change; mode (edit|suggest); expectedRevision; actorKind; label; via
}The document session façade is the single dependency of UI features (W6, W9, W10, W12, W13)
on the editor/sync core. A FakeWriteDocumentSession (pure in-memory Delta, no super_editor)
ships in M0 so feature UIs and their tests can start before the editor exists.
abstract interface class WriteDocumentSession {
UuidValue get documentUuid;
ValueListenable<int> get revision;
Delta get document; // canonical current local document
Stream<AppliedChange> get changes; // {delta, source: local|remote|undo|ai, authorId, revision}
ValueListenable<DeltaSelection?> get selection; // Delta offsets
ValueListenable<Role> get role;
ValueListenable<EditorMode> get mode; // editing | suggesting | viewing
ValueListenable<DocumentMetaState> get meta; // title, themeId, pageSetup, language, frontMatter
Future<void> applyLocal(Delta change, {required String undoLabel, UndoGrouping grouping = UndoGrouping.none,
String? via}); // goes through suggestion rewrite in Suggesting mode
Future<void> updateMeta(DocumentMetaPatch patch, {required String undoLabel});
void select(DeltaSelection selection, {bool reveal = true});
TrackedRange track(int start, int length); // auto-transformed through every applied change
Rect? rectForOffset(int offset); // layout geometry (null in fakes/headless)
}
abstract interface class DocumentSyncController {
SyncState get state; // synchronized | awaitingAck | awaitingAckWithBuffer | offline
int get revision;
void submitLocal(Delta change, {OpKind kind});
Stream<RemoteOpEvent> get remoteOps;
void addTransformListener(TransformListener l); // selection, undo stacks, tracked ranges
}
abstract interface class WriteStylesheetBuilder {
WriteEditorStyle build(ResolvedWriteTheme theme, {required LayoutMode layout, required AppTokens app});
}
abstract interface class EditorLayerRegistry { // W9/W10/W12 contribute layers without touching W3 code
void register(EditorLayerContribution contribution);
}| Shared file | Rule |
|---|---|
lib/commands/commands.dart (Write) |
One line per workstream: registerThemeCommands(r); registerExportCommands(r); … — each workstream owns its *_commands.dart. |
Menus (config/menus.dart) |
MenuSpec built from contributions keyed by menu path + group id (MenuContribution(path: 'Format', group: 'theme', items: […])); workstreams own their contribution files. |
Toolbar (config/toolbar.dart) |
Same contribution pattern with priorities. |
| Routes | Write route table lists /d/:uuid, /d/:uuid/history (W10), /d/:uuid/print (W8), /themes/:uuid (W7) via per-feature route builders. |
server.dart, endpoint registration |
Generated by Serverpod; services registered in src/write/write_module.dart with one call per workstream. |
| Serverpod models | Each workstream owns its .spy.yaml files; migrations created by the workstream that changes models, rebased in order of merge (CI checks a single migration head). |
wonky_core/lib/mcp/write_tools.dart |
Owned by W11; W7/W9/W10 submit tool definitions via write_tools/<area>.dart part files. |
| Editor layers / request handlers / reactions | Registered through EditorLayerRegistry / EditorPipelineRegistry (W3 provides; others contribute). |
graph LR
W0[WS-W0 test infra] --> W1
W1[WS-W1 core model] --> W2[WS-W2 server OT]
W1 --> W3[WS-W3 editor integration]
W1 --> W8[WS-W8 import/export/print]
W1 --> W11[WS-W11 MCP tools]
W2 --> W4[WS-W4 sync client]
W3 --> W4
W4 --> W5[WS-W5 undo]
W3 --> W6[WS-W6 UI chrome]
W3 --> W7[WS-W7 themes]
W7 --> W8
W3 --> W13[WS-W13 images/tables/mentions]
W2 --> W9[WS-W9 comments & suggestions]
W3 --> W9
W2 --> W10[WS-W10 history & presence]
W3 --> W10
W2 --> W11
W9 --> W11
W10 --> W11
W11 --> W12[WS-W12 AI]
W9 --> W12
Interface-level dependencies are satisfied in M0/M2 week 1 by stubs, so the critical path is only the implementation chain W1 → W2/W3 → W4 → W5 (M2), then W9/W10 (M4), then W11 → W12 (M6). W7 and W8 core work (resolver, dark derivation, IR exporters, pagination engine with synthetic metrics, importers) runs in parallel from M2 onward because it depends only on W1.
Suggested staffing (agents or engineers) and lanes:
| Lane | M0 | M2 | M3 | M4 | M5 | M6 |
|---|---|---|---|---|---|---|
| A | W0, W1 contracts | W1 | W1 perf | W9 core (rewriter, ops, views, overlay index) | W8 DOCX/ODT/RTF | W11 |
| B | W2 contracts, S2 | W2 | W2 hardening | W9 server + W10 server | W8 endpoint/import pipeline | W11 |
| C | W3 spike S1 | W3 | W3 IME QA | W9 UI (margin, cards) | W13 tables | W12 server |
| D | W4/W5 contracts | W4, W5 | W13 images, mentions | W10 UI (history, cursors) | W8 PDF + print | W12 client |
| E | — | W6 | W6 | W6 (collab chrome) | W7 theme editor | W6 polish |
| F | fonts pipeline (W7) | W7-lite | W7 core (resolver/dark/contrast) | W8 core (IR, pagination, HTML/EPUB) | W7 built-ins + goldens | — |
A task is done when:
- Code is in the owning workstream's folders; shared files touched only via registrations.
-
dart analyzeclean (strict modes),dart format, dependency-rule check passes (no Flutter inwonky_write_core). - Every new user-visible action is a command
write.<area>.<action>with title, description, args schema,isEnabled,requiredRole, default bindings, and appears in menus/toolbars via contributions; it has an execute → undo → redo test (or is declared non-undoable with reason). - New mutations of document content go through
WriteDocumentSession.applyLocal(client) orHeadlessDocumentEditor(server) — never by editingMutableDocumentnodes directly (exceptDeltaApplier). - Results validate with
WonkyDeltaValidator; new Delta shapes are covered by the OT fuzzer generators (W0) and, if relevant, by commenter-shape validation tests. - Light and dark verified (goldens for new visual components); keyboard operable; semantics labels; strings in ARB files.
- Offline behaviour defined and tested (works offline / disabled with tooltip).
- MCP: if the feature changes document state, a headless tool or
ui.invoke_commandpath exists and has an integration test through/mcp. - Performance budget for the touched path measured (keystroke, remote op, open, export) in the perf suite when applicable.
- Spec updated if behaviour differs from the spec (same PR).
| # | Spike | Question | Exit |
|---|---|---|---|
| S1 | DeltaApplier on vendored super_editor |
Shape of patch SE-2 (incremental, composer-free apply): can remote edits be applied without moving the local caret or breaking IME composition, on web and macOS? | Prototype patch + test with concurrent typing at 20 ops/s |
| S9 (M2–M5) | SE-4 editable tables in vendored super_editor |
Effort and approach for caret/selection inside table cells; event model for embed replacement | Prototype or decision to stay with the popover editor for v1 |
| S2 | Serverpod streams fan-out | Ordering/latency of session.messages with Redis for doc:<uuid> at 100 clients |
< 250 ms p95 locally; gap-fill path proven |
| S3 | ChangeDeltaExtractor fast path coverage |
Which super_editor events lack detail → line-diff fallback frequency and cost | Fallback < 1 ms per node on 100-page doc |
| S4 (M5) | docx_creator 1.4.0 |
Criteria in 07 §5.5 | Adopt / custom writer decision recorded |
| S5 (M2) | Pure-Dart syntax highlighter (re_highlight vs highlight) |
Web compatibility, speed for 2k-line blocks, grammar coverage | Choice recorded in 06 §2.5 |
| S6 (M5) | pdf line metrics |
Adapting pw.RichText into WonkyParagraph with line ranges; font fallback; justification |
Prototype paginating the corpus with widows/orphans |
| S7 (M5) | Web export performance | Cooperative chunked PDF export on the main isolate for 50 pages | ≤ 8 s, UI stays responsive (no frame > 100 ms) |
| S8 (M2) | Web font loading | FontLoader from assets: without startup download; layout shift handling |
Measured startup bytes unchanged |
| Level | Tooling | Write scope | Owner |
|---|---|---|---|
| Unit | test |
Schema validator/normalizer, Markdown codec, IR, address resolver, DocumentEdits, theme resolver/dark/contrast, CSS/style mappers, pagination engine (synthetic metrics), importers/exporters (fixture → expected), page setup, suggestion rewriter/ops/views, overlay index, attributed diff, margin layout, context builder |
each WS |
| Property / fuzz | seeded generators (W0), test |
Markdown round trip; OT convergence (N clients, delays, reorders, disconnects, overlays, suggestions, accepts, restores); undo-all invariant; applier ≡ compose; mapper round trip; exporters never throw + structurally valid; suggesting never changes the original view; random HTML import validity | W0 + each WS |
| Widget | flutter_test |
Editor behaviours (04 ACs), menus/toolbar states from MenuSpec, dialogs, panels, margin cards, theme editor, print preview, AI preview overlay; every command execute→undo→redo through CommandDispatcher with a real WriteDocumentSession on super_editor |
each WS |
| Golden | Flutter goldens (fonts loaded), PDF raster goldens (pdftoppm) |
Editor rendering per built-in theme × light/dark × pages/pageless × zoom 100/200; suggestion/comment rendering; history diff; PDF pages per theme | W7, W8, W9, W10 |
| Server | serverpod_test (withServerpod, embedded Postgres) |
DocumentEndpoint stream (all messages, roles, commenter shapes), OT service, snapshots/pruning, meta changes, theme/export/history endpoints, overlay transitions, notifications, MCP route tools |
W2, W7–W11 |
| Integration / E2E | flutter_driver via the dart MCP + serverpod MCP (spawn_flutter_app), integration_test, two app instances |
Journeys 1–3, 5–9 (Write parts): co-editing convergence, offline/online, comment & suggest/accept, restore + undo, export/import, theme editor, MCP-driven editing (write.* + ui.*) |
W0 + owners |
| Export validation | CI container: LibreOffice headless, epubcheck, Nu checker, ODF validator, poppler | Every exporter on the corpus | W8 |
| Performance | benchmark_harness, profile traces |
Keystroke latency on 100 pages, remote op apply, open (cached/uncached), stylesheet rebuild, pagination incremental, export times, diff computation | W0 + owners |
CI gates: unit + property (fixed seeds plus 1 random seed logged per run) on every PR; widget +
golden on every PR touching Flutter packages; server tests on server changes; E2E and validator
suites nightly and before merge to main for W2/W3/W4/W8 changes; perf suite nightly with
regression alerts (> 10 %).
| Risk | Mitigation |
|---|---|
super_editor cannot apply remote edits cleanly (caret/IME) |
S1 early; fix in the vendored copy (SE-2); isolate in W3 behind WriteDocumentSession |
Vendored super_editor diverges from upstream |
Small, logged patches (PATCHES.md), upstream PRs, deliberate re-sync per upgrade (suite 01 §2.3) |
Event mapping gaps make ChangeDeltaExtractor incorrect |
Debug invariant check (02 §4.4), line-diff fallback, fuzzing with real editor commands |
| Pagination mismatch between editor (approximate) and PDF (exact) | Shared theme metrics; editor hint; P1 line-level split reusing the engine (07 §7) |
| DOCX fidelity across Word/LibreOffice/Google Docs | Validator CI + manual release checklist; conservative OOXML subset |
| AI edits destroying collaboration overlays | Minimal-diff replacement everywhere (DocumentEdits.replaceRange), tests with anchors |
| Spec drift between parallel teams | Contracts + conformance tests; spec updates in the same PR; weekly contract review |