Reuse the companion's prose.ts rules engine as the single source of
deterministic detection instead of duplicating it. Applyable rules now
also emit exact-span fixes (original -> replacement) that surface as
suggestion cards; awareness-only rules (run-ons, splices, ...) stay
companion bubbles. The companion hides fix-bearing hints so a span is
never both a bubble and a card.
Spans are widened to a distinctive phrase ("a old" -> "an old",
"She have" -> "She has") so they re-anchor by string in the editor; a
lone lowercase "i" stays awareness-only since a single char can't anchor.
Backend: detection lives client-side, so the new persist-only
POST /docs/{id}/mechanics endpoint receives findings and stores them as
the 'mechanics' family with their exact offsets. It honours
actioned-suppression, leaves the LLM families untouched, and a checkpoint
no longer wipes it. fetchPending dedupes spans with mechanics winning any
collision against an LLM card (its span is exact). Migration 0008 adds the
'mechanics' suggestion type.
Client renders the mechanics fixes immediately (no LLM wait) and the cards
use a calm sage "Tidy-up" accent.
Verified end-to-end in a real browser on millenia: detect -> persist ->
render -> accept applies the fix.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Replace the kitten's random generic tips with a deterministic, LLM-free
prose checker that reads the actual document and surfaces one gentle,
bilingual note at a time — quoting a slice of her own sentence so the
advice is clearly about *this* draft.
Rules (all conservative, tuned for a Mandarin-native ESL writer):
run-ons, comma splices, unclear antecedents, Oxford comma, a/an,
uncountable plurals, capitalize languages/days/months, subject-verb
agreement, plural-after-number, double determiner, "there is" + plural,
its/it's, than/then, comma-after-transition, doubled words, lowercase
"i", sentence capitals, and spacing around punctuation.
Each rule is paired with false-positive guards (e.g. "a university",
"After dinner, I went home and read", existing Oxford lists) and pinned
by a 45-case Vitest suite (npm test).
Also: bubbles now linger proportional to how much there is to read
(zh+en) and pause-on-hover, so denser advice no longer vanishes mid-read.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd