The pass announces the verdict it just decided

Storing doc_lang on the document row is not enough on its own. The
editor sees that row when the document is opened or saved, and the pass
that decides the verdict runs after a save — so the client was always
one save behind, and read-aloud is reached for precisely when she has
stopped typing and no further save is coming. Heard in a browser: a
Portuguese paragraph read in an American voice, twice, until another
keystroke went in.

/check, /voice and /collocation now answer with X-Petal-Doc-Lang. A
header rather than a wider body: all three answer with a bare array of
the unified pending set and every caller reads it as one, and a verdict
is metadata about the pass rather than another suggestion. It reaches
the app through the same handler shape onUnauthorized already uses.

Claude-Session: https://claude.ai/code/session_01GJHNvirh7Hzhc9RL3HAvz7
This commit is contained in:
prosolis
2026-07-29 00:21:15 -07:00
parent c719effe1d
commit e67f77eb05
4 changed files with 114 additions and 5 deletions
+13
View File
@@ -329,6 +329,19 @@ func (h *Handler) runPass(w http.ResponseWriter, r *http.Request, limiter *llm.R
// Portuguese while she clears it to start the entry again.
docLang := documentLang(contentText, pairLang, prevLang)
// Announce the verdict on every answer this pass gives, including the early
// ones below. This pass is the only thing that decides the value, so it is
// the only moment the client can learn it promptly — and the client needs it
// promptly for read-aloud, which is reached for exactly when she has stopped
// typing and no further save is coming. Carrying it back on the document row
// alone means the editor is always one save behind the truth, and a paragraph
// of Portuguese read in an American voice is how that sounds.
//
// A header rather than a wider body: /check and /voice answer with a bare
// array of the unified pending set, and every caller of both endpoints reads
// it as one. A verdict is metadata about the pass, not another suggestion.
w.Header().Set("X-Petal-Doc-Lang", docLang)
// Nothing to analyze on an empty document — skip the LLM round-trip. The
// family's rows go with the text they were about.
if strings.TrimSpace(contentText) == "" {