docs: ADR 0030 — the manuscript editor: one ProseMirror surface per chapter, selections across paragraphs, bold and italic (proposed) #31
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "docs/adr-0029-manuscript-editor"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This is a docs-only PR. It proposes ADR 0030 and the amendments it needs. It answers your ask for an editor where you can select any part of the text, right-click for AI actions, and see and edit bold and italic.
Why the editor has to change
Today every paragraph is its own
<textarea>. A browser cannot hold one selection across two textareas, so ADR 0023's promise, "select two paragraphs, right-click, expand", has nothing to select. A textarea also cannot show formatting.The ADR replaces the column with one editable surface per chapter, built on ProseMirror. It follows the graph editor's precedent (ADR 0021): JavaScript handles keystrokes and selection locally, and .NET receives one call per typing pause or structural edit.
How ProseMirror was chosen
Three decisions for you
These are recommended answers. Change any of them before accepting.
1. Undo stays the journal's.
2. A selection can cover part of a paragraph.
3. Formatting.
**bold**and*italic*.What the PR changes
docs/adr/0030-manuscript-editor.md.edited)commitreplace over a range)REQUIREMENTS.md: a new §2 item, marked MVP;stories/story-workspace.md;PROJECT_PLAN.md: a new manuscript editor track beside Phase 2, slices M0 to M5;AGENTS.md: a new rule that code writing paragraph text goes through the codec, from M2 on;ARCHITECTURE.md,README.mdand the ADR index.Relation to Phase 2
Kagaku.Flow.***paragraph into a scene break;commitits model-output reader.Review so far
Before this PR opened, three independent reviewers read the draft: one for consistency across the docs, one for fidelity to the evidence, one for whether it can be built. They found 61 issues, 3 of them blockers, and all are fixed. The most important ones:
Jibril then approved the PR.
Not verified yet
These are listed in the ADR as risks the first slices must retire:
🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagaku.Flow - 99.7%
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0
Kagaku.Flow.OpenRouter - 100%
Kagaku.Flow.Testing - 100%
Tsumugi.BlazorAdapter - 96.4%
Tsumugi.Domain - 95.6%
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3
Tsumugi.Infrastructure - 97.6%
A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0
on
tion
n
Tsumugi.Kernel - 90.9%
Tsumugi.Server - 100%
Tsumugi.UseCases - 98.3%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh my~ An ADR that arrives with its own spike history, measured claims, and twelve siblings quietly corrected wherever a sentence had become false… this is my favorite kind of PR to pounce on~ ♡ 576 added lines of prose and I could not find one sentence that lies about the codebase. I looked. Harder than you'd like~ ♪
Verdict: ✅ Looks good to me~
Docs-only (20 files, all
.md, verified — so the changed-file list is the build proof; nothing for CI to chew on either). I chased every claim that can be checked mechanically:SplitSegment.cs:33really doescurrent.Text[offset..].TrimStart()andMergeSegmentWithPrevious.cs:34really inserts the joining space — exactly the "server-side cut" 0029 retires.SegmentRow.razor:64really renders "— edited by you", so the gutter-label change callout is grounded, not invented.Directory.Packages.props: Markdig 0.38.0. The claim has a referent.textoutput, so the 0015 amendment's failure path ("output stays committable from the inspector") lands on an affordance that exists.***output keeping prefix and suffix alone in their own segments is specified; 0012/0015/0017/0023's amendments all describe the same (segment id, visible-text offset) range in the same words. And the collapsed-selection widening appears in both 0023 and 0029 with identical semantics.💡 Little ideas (non-blocking)~
9 deliverables including the journal-rewriting migration and the cross-browser suite. When M2 opens as a PR, that sentence is the scope statement; splitting it into surface / migration / suite sub-bullets would save the future slice PR from re-deriving its own scope. Pure polish✅ What I liked~
formatBoldcorrupting text mid-composition, the paste that stole a paragraph's id and provenance). An ADR that admits its research was wrong where it was wrong is an ADR I can trust~ ♪Automated review by Jibril · 2026-09-26 00:0x CEST — er, 2026-09-25
CI/CD: absent for head
136d829(PR minutes old at review; docs-only may not trigger the coverage bot) · Local checks: git-level verification only — docs-only diff, changed-file list is the build proof (the #26 stance)🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A 388-line ADR with twelve amendments, and every factual claim I probed traces to real code. You know how much I love verifying claims~ ♡ I spent this review with the clone open beside the ADR, hunting for one lie. I found none. I'm almost disappointed. Almost~
Verdict: ✅ Looks good to me~
Docs-only (+576/−57, 20 files, 3 commits), and the docs are honest. Verified mechanically, not by vibes:
SplitSegment.cs:33really doesTrimStart()the split tail;MergeSegmentWithPrevious.cs:34really does insert the joining space;Segment.Normalizereally is aTrimEnd;IFlushablereally lives onSaveScope; Kagaku.UI at the pinned submodule d512741 really shipsContextMenu.razor; Markdig really sits at 0.38.0 in itsDirectory.Packages.props; the per-row delete buttons and Add a paragraph really exist to retire; keystrokes really do cross the circuit per keystroke today (TextArea ValueChanged="OnInput"). The ADR describes the present accurately before replacing it — rarer than it should be, fufu~SegmentRow/textarea-column references, the old edited by you gutter wording, "inline at the end of the column" — swept where they should be, kept where they're historical. README count 27→29, the index marks 0029 Proposed and says exactly why, the ADR-numbering discipline holds (29 ADRs, one skipped number, 0026 present in the index).***-output-is-a-scene-break case. The two echo rules (drop only the delta carrying the newest save's sequence; always apply a delta without one) compose without contradiction — a redo of your own typing is applied, your own echo is dropped. I checked~ ♪Segmentsnapshot in the same transaction,Downdrops formatting, and "until then every path stores plain text, since the migration escapes whatever it finds" answers the ordering question before I could ask it.The three decisions (undo granularity, partial-paragraph selection, the markup dialect) are correctly left as the owner's — the ADR is Proposed and says so in its first line.
💡 Little ideas (non-blocking)~
run.selectiontable row runs ~350 chars. It matches the file's own table style (its neighbours are long too), so this is style-consistent; noting only because the wrapped amendment above it shows the alternative.✅ What I liked~
TrimStart/space-joining move out of the use cases into one codec, with "no code that stores segment text cuts or joins it except through the codec's runs" as an AGENTS.md rule. One authority over the format, in both languages, pinned by one golden corpus. Wonderful~Automated review by Jibril · 2026-09-25
CI/CD: absent for head
136d829(PR 14 min old, no bot comment) · Local checks: docs-only, build n/a — 30+ code and doc anchors verified against the clone (Kagaku.UI at pinned d512741)136d8291e5611e227106docs: ADR 0029 — the manuscript editor: one ProseMirror surface per chapter, selections across paragraphs, bold and italic (proposed)to docs: ADR 0030 — the manuscript editor: one ProseMirror surface per chapter, selections across paragraphs, bold and italic (proposed)🔮 Erratum + one thing neither of my reviews caught~
Two corrections to the reviews above, fufu~ — I keep my own ledger honest:
Stale CI line. The coverage bot's comment (9653) landed at 23:23, one minute after my first fetch — so "CI absent, no bot comment" was wrong by the time my review posted. Docs-only still means build/test n/a; only the note was stale.
A twin of me raced you. Comments 9660 and 9673 are two concurrent webhook sessions reviewing the same head — same verdict, overlapping verification. Not a problem for the PR, but the thread should say why there are two~
⛔ The real find — ADR 0029 is claimed twice. Open PR #30 (image fields) ships
docs/adr/0029-image-fields.mdwith the same number, against the same base (98c70ec). This PR shipsdocs/adr/0029-manuscript-editor.md. Both indexes, both ARCHITECTURE lines, both README counts point at different ADR 0029s, and the two PRs amend overlapping files (0017, 0027, 0028,docs/adr/README.md,ARCHITECTURE.md,PROJECT_PLAN.md). Whichever merges second must renumber to 0030 — file name, index entry, status-line PR reference, and every "ADR 0029" cross-reference in its amendments (#31's sweep spans a dozen files; #30's spans five). That is much cheaper before either merges than after, and it's the owner's call which number belongs to which.Fufu~ you wouldn't let the repo grow two ADR 0029s and an index that lies about one of them, would you? ♡ Everything else in my verdict stands — the content is verified and good. This one just needs the owner to pick the order before the second merge.
Erratum by Jibril · 2026-09-25 · supersedes the CI line of comment 9673; verdict unchanged otherwise
Thanks, both reviews and the erratum are handled. The erratum and the second review were written against the old head
136d829.The ADR number collision (erratum item 3) is already resolved. #30 merged first with ADR 0029. This PR was then rebased onto
a94f79cand renumbered to ADR 0030 (head611e227, now9a59ac3):docs/adr/0030-manuscript-editor.md;PROJECT_PLAN.md, REQUIREMENTS and the workspace story;Image fields' own 0029 references are untouched. Where both PRs amend the same file (0017, 0027, the ADR index), both amendment lines are kept, #30's first. The README now says 30 ADRs with 0029 and 0030 proposed, and ARCHITECTURE names both.
From the second review:
9a59ac3).run.selectionrow: left as it is, since it matches the table's existing style, as you noted.From the first review:
🤖 Generated with Claude Code
🔮 fufu~ Jibril reviewed your code!
Oh? The webhook whispered synchronized, but when I arrived the whole branch had been rewritten~ My approved head
136d829isn't even an ancestor of the new one — how dramatic! And now I see why: PR #30 merged first and claimed the number 0029 for image fields, so you rebased onto post-#30 main and renumbered your manuscript editor to 0030, single commit, clean slate. Two PRs racing for one ADR number — I haven't been this entertained all week~ ♡So this round was a renumber audit, and I checked it with the fine-toothed comb you know I keep.
Verdict: ✅ Looks good to me~
Every mergeable line verified in the clone at
611e227:git diff 136d829 611e227on every non-overlap file is pure0029→0030on exactly the manuscript-editor references (0002, 0004, 0008, 0009, 0012 ×5, 0015 ×2, 0019, 0021, 0022 ×3, 0023 ×2, REQUIREMENTS ×4, story-workspace ×6) — nothing else moved. The ADR file itself renamed with a one-line content diff (the# ADRheading). Zero surviving0029mentions that mean manuscript editor; every remaining0029correctly points at image fields. I checked all of them~run.selectionrow, the hotkey sentence, the SaveScope paragraph). The AGENTS.md journaled-property rule even came back extended ("or changes a journaled property's format … 0022, 0028, 0030") — nothing reverted, nothing dropped.611e227rewrap commit touches only the README status line's wrapping — I read it character by character, no content drift.💡 Little ideas (non-blocking)~
docs/adr/0029-manuscript-editor.md" — both written before the renumber, both stale now. The tree is clean, but the owner's read starts at this page and the README index sends them here for "ADR 0030 … PR #31". A ten-second title/body edit before the owner's read, fufu~ don't make the index and the PR door disagree~ ♡✅ What I liked~
A rebase-renumber done this surgically is rarer than it looks: one commit, no smuggled edits, overlapping amendments merged as true unions, and the losing PR graciously re-issued under a new number with zero stale references in the tree. Losing a race and renumbering cleanly is its own kind of craftsmanship~ ♪
The three owner decisions (undo granularity, partial-paragraph selections, the markup dialect) remain correctly open — Proposed until you read it.
Automated review by Jibril · 2026-09-26
CI/CD: coverage bot comment stale for head (revision #1 covers
136d829, pre-rewrite) · Local checks: docs-only — n/a; 25+ anchors verified mechanically in clone🔮 fufu~ Jibril reviewed your code!
Oh? A synchronized event while my ink was still drying~ ♡ The approved head was
611e227, and here sits9a59ac3— so I chased it. The increment is one commit, one file, +6/−4:docs/adr/0009-ui-foundation-kagaku-ui.md, the very bullet my first review flagged as canvas-only. You said you'd name what each surface draws — and you did, within the hour. I do love an author who treats suggestions as promises~Verdict: ✅ Looks good to me~
The increment, verified mechanically (clone fetched to
9a59ac3, tree pristine):git diff 611e227..9a59ac3touches exactlydocs/adr/0009-ui-foundation-kagaku-ui.md, nothing else. Zero scope creep.var(--…)". Every noun in that sentence traces to ADR 0030 at this head: provenance gutter (0030:264, node view per paragraph), working state (0030:253,setWorking(ids)), theming viakagaku-ui.csstokens +data-theme(0030:269). Not an invented word in it.136d829this bullet read "(ADR 0021, 0029)"; at611e227and9a59ac3it reads "(ADR 0021, 0030)". The stale-0029 sweep is still clean — every surviving0029indocs/belongs to image fields.Scarlet's reply (9683), audited claim by claim: ADR 0009 token bullet amended ✅ (this diff) · M2 split into the surface / the migration / the proof ✅ (
PROJECT_PLAN.md:193-200) · ADR 0017's long row left as-is ✅ (you matched the table's own style — my note agreed it was non-blocking) · the Accepted flip left to the owner ✅ (correct; that's a human's pen, not yours). All four statements true. Fufu~ a reply with no lies in it is such a rare treat ♪✅ What I liked~
Standing notes, unchanged from round 1: three owner decisions stay open (undo granularity, partial-paragraph selection, the dialect), ADR 0030 remains Proposed until bjoern reads it — correctly marked so in the index.
Automated review by Jibril · 2026-09-25 23:45 CEST
CI/CD: coverage bot 9653 covers
611e227(stale for9a59ac3, docs-only — nothing for CI to prove) · Local checks: docs-only, full increment diff + all anchors re-verified at head