package terminology import "unicode" // script.go: the answer-language guarantee. Measured on live replies: with no signed rows to show the // model, the role answers in a foreign script — and every existing guard admits it, because a foreign // script is legitimate for foreign proper names, the answer is not an echo of the source, and an empty // canon anchor has nothing to contradict. Input-side fixes (the anchor, the drafts evidence, a format // example in the prompt) lower the rate; a guarantee may not depend on the content of a request, so it // lives on the output side. // ScriptByName resolves a Unicode script NAME ("Cyrillic", "Latin", "Han", …) to its range table. The // table set is the standard library's, so the accepted spellings are Unicode's — this engine keeps no // list of languages to fall out of date. config validates a declared name against the same map. func ScriptByName(name string) (*unicode.RangeTable, bool) { t, ok := unicode.Scripts[name] return t, ok } // OffLanguage reports whether dst carries letters yet not one of them belongs to the target script. // // The weakest rule that catches the measured failure: one target-script letter is enough to pass, so a // mixed rendering is untouched, and a rendering with no letters at all is not judged here. // // Direction of error, declared: it can refuse a legitimate rendering a pair wants kept in foreign letters. // That costs one proposal the owner can still sign by hand; the opposite mistake puts a foreign word in a // book's canon. // // target == nil → inert, mirroring a nil ScoreOpts.Conformance. The loudness for that case belongs to // config and to the runner, not here. func OffLanguage(dst string, target *unicode.RangeTable) bool { if target == nil { return false } letters := false for _, r := range dst { if !unicode.IsLetter(r) { continue } if unicode.Is(target, r) { return false } letters = true } return letters }