80 lines
4.5 KiB
Go
80 lines
4.5 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"textmachine/backend/internal/lang"
|
|
"textmachine/backend/internal/langscreen"
|
|
"textmachine/backend/internal/llm"
|
|
)
|
|
|
|
// cjktarget_screen_test.go pins that the target-language screen runs for a CJK TARGET.
|
|
//
|
|
// ⚠ IT DID NOT, AND THE DOC COMMENT SAID IT DID. The echo rule and the screen sat under one gate,
|
|
// `!isCJKTarget(target)`, so →ja / →zh / →ko books were screened by nothing at all — while langscreen's own
|
|
// header promised «a →ja one is screened against everything that is not han/kana». The two rules ask
|
|
// opposite questions and only ONE of them is meaningless for a CJK target: «is the output in the SOURCE's
|
|
// script» cannot be asked of a →ja rendering of a zh book (a correct one is full of han), but «is the output
|
|
// in the TARGET's script» is perfectly answerable and an English completion fails it.
|
|
//
|
|
// This is a goal-2 test, not a nicety: the standing review question is «does a pair the repo has never seen
|
|
// work without editing Go», and for every CJK target the answer was no.
|
|
|
|
func TestACJKTargetIsScreenedToo(t *testing.T) {
|
|
english := strings.Repeat("The librarian walked the long corridor and remembered the lecture. ", 8)
|
|
if n := countLetters(english); n < langscreen.MinLetters {
|
|
t.Fatalf("premise broken: fixture must clear the evidence floor, got %d letters", n)
|
|
}
|
|
in := func(out, target string) classifyInput {
|
|
return classifyInput{Output: out, Finish: llm.FinishStop, TargetLang: target,
|
|
SourceScripts: lang.LangScripts("zh"), TargetScripts: lang.LangScripts(target)}
|
|
}
|
|
for _, target := range []string{"ja", "zh", "ko"} {
|
|
if !lang.IsCJKScriptLang(target) {
|
|
t.Fatalf("premise broken: %s must be a CJK-script target for this test to mean anything", target)
|
|
}
|
|
got := classify(in(english, target))
|
|
if got.Reason != FlagOffTargetLang {
|
|
t.Errorf("→%s: an English completion must flag off-target, got %q (%s)", target, got.Reason, got.Detail)
|
|
}
|
|
}
|
|
|
|
// A HEALTHY completion in the target must stay clean — otherwise the fix above would have bought the
|
|
// screen by making every CJK book unshippable.
|
|
japanese := strings.Repeat("彼は長い廊下を歩きながら、講義のことを思い出していた。", 14)
|
|
if n := countLetters(japanese); n < langscreen.MinLetters {
|
|
t.Fatalf("premise broken: the healthy fixture must clear the floor too, got %d letters", n)
|
|
}
|
|
if got := classify(in(japanese, "ja")); got.Reason != reasonOK {
|
|
t.Errorf("a healthy Japanese completion for a →ja book must pass, got %q (%s)", got.Reason, got.Detail)
|
|
}
|
|
|
|
// ⚠ AND THE DOCUMENTED MISS, asserted as a miss. ja declares han, so a purely CHINESE completion for a
|
|
// →ja book scores 1.000 and is NOT flagged. That is the superset limit langscreen's header names, it is
|
|
// a property of the question and not a defect of this wiring, and it is pinned here so that a future
|
|
// reader cannot mistake this screen for protection against a zh echo on a →ja book.
|
|
chinese := strings.Repeat("方源看着蛊,那是一只月光蛊。", 30)
|
|
if got := classify(in(chinese, "ja")); got.Reason == FlagOffTargetLang {
|
|
t.Error("the superset limit changed: a Chinese completion for →ja is now flagged off-target. That may " +
|
|
"be an improvement, but langscreen's header documents the miss and this test records it — update both together")
|
|
}
|
|
}
|
|
|
|
// TestTheEchoRuleStaysOffForACJKTarget is the other half, and it is what stops the fix above from being an
|
|
// over-correction: lifting the screen out of the gate must NOT lift the echo rule with it, or every correct
|
|
// →ja chapter would be flagged as an untranslated echo of its Chinese source.
|
|
func TestTheEchoRuleStaysOffForACJKTarget(t *testing.T) {
|
|
chinese := strings.Repeat("方源看着蛊,那是一只月光蛊。", 30)
|
|
got := classify(classifyInput{Output: chinese, Finish: llm.FinishStop, TargetLang: "ja",
|
|
SourceScripts: lang.LangScripts("zh"), TargetScripts: lang.LangScripts("ja")})
|
|
if got.Reason == FlagCJKArtifact {
|
|
t.Fatal("the echo rule fired for a CJK TARGET: «the output is in the source's script» is not a " +
|
|
"question that can be asked of a →ja book, and asking it flags every correct chapter")
|
|
}
|
|
// A →ru book keeps the echo rule — the guard against loosening the gate for everyone.
|
|
if r := classify(classifyInput{Output: chinese, Finish: llm.FinishStop, TargetLang: "ru",
|
|
SourceScripts: lang.LangScripts("zh"), TargetScripts: lang.LangScripts("ru")}); r.Reason != FlagCJKArtifact {
|
|
t.Fatalf("a →ru book must still name a source echo an echo, got %q", r.Reason)
|
|
}
|
|
}
|