Addresses all five findings on the previous turn.
The two halves now agree, and by contract #
The set is named once — WRITING_AIDS in packages/ui/src/lib/editor.ts — and given to both
halves of MarkdownEditor: the textarea as spread attributes, the CodeMirror surface through
EditorView.contentAttributes in baseExtensions, beside the Escape and ⌘↵ keymaps that exist for
the same reason a contenteditable needs this at all.
- All four, not two.
@codemirror/viewwritesspellcheck="false",autocorrect="off",autocapitalize="off"andwritingsuggestions="false"ontocontentDOM. Overriding only the first two left a phone capitalizing sentences in the fallback and stopping the moment the lazy chunk landed — mid-draft, with no visible cause, and against the one property the swap exists to preserve.autocapitalize: 'sentences'andwritingsuggestions: 'true'are now in the set, and the reasoning for each is stated where the set is.translateandcontenteditableare left to CodeMirror: they are about the document, not about typing into it. - A facet, not
setAttribute.updateAttrs()recomputes the full default set on every view update and writes back anything differing from its own cached previous value — never from the DOM — so the previous form held only while"false" == "false"stayed true, and would have vanished silently under a CodeMirror release that reordered the defaults or any extension contributing to the same facet. The facet value is merged over the defaults byattrsFromFacetand becomes that cached value, and it is applied inside CodeMirror's ownobserver.ignore(), so the two mount-time writes no longer emit mutation records theDOMObserverreads as a foreign edit.
The test proves the property rather than the call #
MarkdownEditor.svelte.test.ts now reconfigures the view — disabled on, then off, the same beat
the neighbouring disabled test uses — before asserting, so it runs updateAttrs() at least once and
holds the attributes staying. Verified as a real regression test: deleting the facet line fails
it; the previous form of the test passed at the one instant nothing could have clobbered it.
Single-line prose fields (the scope finding) #
Firefox's layout.spellcheckDefault=1 covers multi-line fields only, so an <input> is unchecked
there without an explicit attribute. Opted in: the goal title (NewGoal), the imported goal's title
(userinput/+page.svelte), the space name and a private space's public label (NewSpace), the
private-join label (JoinPrivate), and an artifact type's one-line description (NewType).
Deliberately unchanged, and recorded in the README so the next turn does not re-ask:
- Identifiers keep their existing
spellcheck="false"— handle, project name (it is also the URL), git URL, path, check command, ticket. - Labels (
LabelEditor) and saved-view names (FilterBar) are tags people re-use, not sentences; squiggling a project's own vocabulary back at them teaches nothing. - Bare
<textarea>s (space description, the import body) are spellchecked by default already.
Docs #
packages/ui/README.md's "Writing markdown, and pictures in it" gains two paragraphs — the writing
aids as the same fact as the keymaps, plus why the facet and not an attribute, and the single-line
opt-in list with its exclusions. The component header's "Three things it is careful about" is now
four, with the new one written out.
Provenance and checks #
- Branch
radial/impl-eb11036e6975, rebased ontoorigin/main(1617f05) before implementing. - Commit
9f1e9ecde43051b8c7a36e6f38809cdbcfec912e. pnpm lint— clean (no-NUL check, lexicon codegen check, typecheck across all 10 packages,svelte-check: 686 files, 0 errors, 0 warnings).pnpm test— all packages pass;@radial/uiis 84node --testassertions plus 811 vitest tests across 61 files, including the 26-testMarkdownEditorcomponent suite mounting CodeMirror for real in jsdom.pnpm build— clean, UI bundle written.
Remaining risks #
Both attributes remain browser hints: autocorrect is honoured by Safari and Chromium and ignored
by Firefox, and writingsuggestions is Chromium and Safari only. Nothing here changes what is
written to a record. jsdom does not implement any of the four behaviours, so the test asserts the
attributes reach and survive on the element the browser reads — it cannot assert the browser then
corrects anything.