When she writes in Chinese, say Translate — not Clarity
She reaches for her own language mid-sentence when English won't come, and Petal already handled it: it found the span and rendered it into English. It just filed the result as a Clarity fix, so the pair model's flagship moment read as tidying up her Chinese. The type is now derived from the span rather than asked of the model. A type is structural, and a model that re-reasons every pass would drift between labels for a sentence nobody had touched — the instability the last session spent itself removing. The label the model volunteers is still ignored. Only the grammar checkpoint can be promoted. A pass with a forced type owns its family: voice reads paragraphs for tone and its rows carry no replacement, so a "translation" there would be a card offering nothing to accept. zh is a different script and counting Han runes is close to certain. The Latin pairs share an alphabet with English and get none of that, so they fall back to function words and need two before Petal claims anything — with every word that is also English left out, even the common ones. The heuristic is justified by how cheap being wrong is: it changes a coloured pill, and nothing else. The pill is the one bilingual type name in the rail. Every other type stays English because those are the terms she is learning; this card's whole subject is her own language. And it stops truncating its two lines — elsewhere the diff is a word and the explanation is what she reads, but here the two sentences are the card. Two things only the running page could report. The inline underline was invisible: the decoration carries a per-type class and the base rule is a transparent border, so a type with no colour rule gets no mark at all. And at 1517×810 with the document list open there is no rail — the margin is 258 where railEnabled wants 348 — so what she gets is the inline hover card. Item 7 is written the other way round. Migration 0015 rebuilds the suggestions table for the CHECK, which makes it the first one here that could quietly drop her rows; there is a test that carries every column, both timestamps and both indexes across it. Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
This commit is contained in:
@@ -399,6 +399,106 @@ card's strikethrough line so she can still see what she wrote).
|
||||
card within one check cycle; accepting swaps in the English; an
|
||||
English-only doc and a Chinese-only doc are unaffected.
|
||||
|
||||
### 5 — DONE (sixth session). The label was the whole gap, and it isn't the model's to give.
|
||||
|
||||
The re-scoped premise held: Petal already found the span and already rendered
|
||||
it into English. Only the type was wrong. So the work was to decide that type
|
||||
*structurally* rather than ask for it — a model that re-reasons every pass
|
||||
would drift between labels for a sentence that hadn't changed, which is exactly
|
||||
the instability item 2 just spent a session removing.
|
||||
|
||||
**Implemented:**
|
||||
|
||||
- `language.go` — `isTranslation(original, replacement, pairLang)`. Both halves
|
||||
must hold: the span reads as her language *and* what Petal offers back reads
|
||||
as English. The second half is not decoration — a Chinese span rewritten into
|
||||
different Chinese is something else, and Petal has no business calling it a
|
||||
translation.
|
||||
- `reconcile.go` — the promotion sits at the single point where a type is
|
||||
stamped, and only on the open-typed grammar checkpoint. A pass with a
|
||||
`forceType` owns its family outright: voice reads paragraphs for tone and its
|
||||
rows carry no replacement, so a "translation" there would be a card offering
|
||||
nothing to accept. There is a test for exactly that.
|
||||
- `normalizeType` still refuses `translate` from the model, deliberately. A
|
||||
model that volunteers the label lands on grammar and is then promoted — or
|
||||
not — on the evidence.
|
||||
- Migration `0015` rebuilds the suggestions table for the extended `type` CHECK
|
||||
(SQLite can't ALTER one), as `0005` and `0008` did before it.
|
||||
- Client: `--color-jade`, the `translate` entry in `TYPE_META`, and
|
||||
`.petal-suggestion-translate` for the inline underline.
|
||||
- The pill is the one bilingual type name in the rail — `翻译 · Translate`,
|
||||
`Tradução · Translate`, `Traduction · Translate`, from the pack. Every other
|
||||
type stays English on purpose: those are the terms she is learning, and she is
|
||||
learning them in English. This card's whole subject is her own language.
|
||||
- The rail card stops truncating its two lines for a translation. Elsewhere the
|
||||
original and replacement differ by a word and the explanation below is what
|
||||
she reads; here the two lines are a whole sentence in each language and *are*
|
||||
the card.
|
||||
|
||||
**The pair families need different tests, and pretending otherwise was the
|
||||
trap.** The item's plan says to reuse the CJK detection from spellcheck — which
|
||||
works, for zh, because it is a different script. It gives nothing for pt-PT, fr
|
||||
or es, where no such signal exists. Those fall back to function words, and need
|
||||
two distinct markers before Petal will claim anything; the lists deliberately
|
||||
omit every word that is *also* English (`do`, `con`, `ya`, `todo`, and the
|
||||
pan-Romance shorts), even where that costs a very common one. A single marker is
|
||||
never enough, so a one-word Portuguese span won't trip it — a single word is a
|
||||
vocabulary question, not a translation. The whole heuristic is justified by how
|
||||
cheap its failure is: a wrong answer changes a coloured pill and nothing else,
|
||||
because the replacement, the explanation and the Accept button are identical
|
||||
either way.
|
||||
|
||||
**Two things only the browser could have told me.**
|
||||
|
||||
- **The inline underline was invisible.** The decoration plugin emits a
|
||||
per-type class, and `.petal-suggestion` sets `border-bottom: 2px solid
|
||||
transparent` — so a type with no colour rule renders with no underline at
|
||||
all. Every test passed; the flagship span simply had no mark under it on
|
||||
screen. Found by looking at the page, and it is the reason this doc keeps
|
||||
insisting on that.
|
||||
- **At her viewport there is no rail.** `railEnabled` needs 348 px beside the
|
||||
editor, and at 1517×810 with the document list open the margin is 258 — so
|
||||
the card she actually gets is the inline hover panel, not a rail card. Worth
|
||||
knowing before item 7 is scoped: that item assumes the rail is what she sees
|
||||
and treats the anchored popover as the missing half. On this screen it is the
|
||||
other way round. (The fifth session measured rail cards at the same width, so
|
||||
some state does reach it; not chased here.)
|
||||
|
||||
**Verified against the running binary**, with a stand-in model server so no VPN
|
||||
or GPU was involved. The stub types the Chinese finding `"clarity"` — exactly
|
||||
what the live build did — so the label on screen can only have come from Petal's
|
||||
own detection. Through the real `/check`: `grammar` for the English sentence,
|
||||
`translate` for the Chinese one. In the browser: the jade underline distinct
|
||||
from grammar's mint, and the card showing the `翻译 · Translate` pill, the
|
||||
Chinese struck through and wrapped over two lines rather than clipped, the
|
||||
English rendering, the bilingual explanation, and Accept.
|
||||
|
||||
**Not verified in a browser:** the *rail* card's version of the same thing. The
|
||||
rail is unreachable on this 1517 px display (above), and forcing it by hand kept
|
||||
being overridden by React's own layout. Its label goes through the same
|
||||
`typeLabel` call the hover card just proved, and its diff differs only by a
|
||||
class toggle — but that is a reading, not a measurement, and it is written down
|
||||
as one.
|
||||
|
||||
Coverage: `language_test.go` (the flagship sentence; a lone Han rune; one
|
||||
Chinese word inside English prose; Chinese→Chinese; a Chinese span on the wrong
|
||||
pair; all three Latin pairs; an English sentence stuffed with pan-Romance
|
||||
lookalikes; French elision; unknown and absent pairs), `translate_type_test.go`
|
||||
(the type through the real `/check`, an English correction keeping its own type,
|
||||
and voice unable to mint one), `suggestionMeta.test.ts` (every type has a colour
|
||||
and a name, translate's colour is its own, the pill is bilingual per pair and
|
||||
every other pill isn't), and `db_test.go`'s
|
||||
`TestTranslateTypeMigrationPreservesRows` — 0015 rebuilds the table, so it is
|
||||
the first migration here that could silently *drop her rows*; every column,
|
||||
both timestamps and both indexes are asserted across it.
|
||||
|
||||
One test changed contract: the pt-PT pack's Brazilian-forms grep searched
|
||||
`JSON.stringify(pack)`, which includes field *names* — and duly failed on
|
||||
`translateLabel`, since it lowercases to "transla·tela·bel" and so "contains"
|
||||
the pt-BR *tela*. It now searches the pack's copy only, with two canaries, since
|
||||
every assertion in it is a negative and a haystack that quietly went empty would
|
||||
make the whole test pass by having nothing to search.
|
||||
|
||||
## 6. Ask Petal answers: bilingual, and room to read
|
||||
|
||||
The card's *explanation* is bilingual, but the Ask Petal *answer* came back
|
||||
@@ -504,6 +604,13 @@ vitest tests. So the three sessions of work she hasn't seen, she can now
|
||||
see. Untouched: 6, 7, 8, item 3's incremental half, item 5's re-scoped
|
||||
Translate card type.)*
|
||||
|
||||
*(Sixth session, second half: item 5 done — see the subsection under it. It sits
|
||||
on `feat/translate-card`, **not deployed**; `main` is at the stack merge. Two
|
||||
findings there are worth reading before picking the next item: the inline
|
||||
underline needs a per-type CSS rule or it renders invisibly, and at her actual
|
||||
viewport the rail is disabled — the inline hover card is what she sees, which
|
||||
inverts item 7's premise. Untouched: 6, 7, 8, item 3's incremental half.)*
|
||||
|
||||
**Suggested next (sixth session onward):** items 6, 7, 8 are all untouched
|
||||
and all small; item 5's re-scoped Translate card type is the cheapest
|
||||
*visible* win (see its Status note — the span is already detected and
|
||||
|
||||
Reference in New Issue
Block a user