93 lines
5.2 KiB
Go
93 lines
5.2 KiB
Go
package config
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// TestEnRuPairLayerCarriesItsOwnFertilityEstimate: the generic segmentation fallback is the zh-ru
|
|
// calibration (LoadPipeline says so), so a pair file omitting `fertility.other` chunks an English book
|
|
// on Chinese numbers. The premise — estimate != fallback — is asserted, or the fixture measures nothing.
|
|
func TestEnRuPairLayerCarriesItsOwnFertilityEstimate(t *testing.T) {
|
|
const genericFallbackOther = 0.3852 // the literal LoadPipeline falls back to (zh-ru calibration)
|
|
const enRuEstimateOther = 0.4203 // r/3.64, DeepSeek r=1.53 — an ESTIMATE, see the pair file
|
|
if enRuEstimateOther == genericFallbackOther {
|
|
t.Fatalf("premise broken: the en-ru estimate equals the generic fallback (%v), so nothing below can distinguish the pair layer from the default", enRuEstimateOther)
|
|
}
|
|
models, err := LoadModels(filepath.Join("..", "..", "configs", "models.yaml"))
|
|
if err != nil {
|
|
t.Fatalf("load models: %v", err)
|
|
}
|
|
cfg := filepath.Join("..", "..", "configs", "pipeline-c1.yaml")
|
|
|
|
en, err := LoadPipeline(cfg, models, "en-ru", nil)
|
|
if err != nil {
|
|
t.Fatalf("pipeline-c1 must load for en-ru: %v", err)
|
|
}
|
|
if got := en.Segmentation.Fertility.Other; got != enRuEstimateOther {
|
|
t.Errorf("en-ru fertility.other = %v, want %v from configs/pairs/en-ru.yaml — %v would mean the pair file is not read and the English book is being chunked on the zh-ru calibration",
|
|
got, enRuEstimateOther, genericFallbackOther)
|
|
}
|
|
// cjk is deliberately UNSTATED for en-ru (dense runes measured 0 in 351 of 351 units of the live
|
|
// book, so the coefficient multiplies zero); the fallback is therefore expected, and asserting it
|
|
// keeps "unstated" from drifting into "stated by accident".
|
|
if got := en.Segmentation.Fertility.CJK; got != 1.1978 {
|
|
t.Errorf("en-ru fertility.cjk = %v, want the fallback 1.1978 — the pair file states no cjk value on purpose", got)
|
|
}
|
|
// The budgets are target-side (ru OUTPUT tokens), so en-ru keeps the fallback deliberately too.
|
|
if en.Segmentation.DraftBudgetOut != 1797 || en.Segmentation.EditCeilingOut != 3200 {
|
|
t.Errorf("en-ru budgets = %d/%d, want the fallback 1797/3200 (they are measured in ru output tokens, a target-side quantity)",
|
|
en.Segmentation.DraftBudgetOut, en.Segmentation.EditCeilingOut)
|
|
}
|
|
if got := en.Gates.Coverage.LenRatio["en-ru"]; len(got) != 2 || got[0] != 0.70 || got[1] != 1.4 {
|
|
t.Errorf("en-ru corridor = %v, want [0.7 1.4] from the pair layer", got)
|
|
}
|
|
|
|
// And the other direction: the zh-ru pair must be untouched by the English file existing.
|
|
zh, err := LoadPipeline(cfg, models, "zh-ru", nil)
|
|
if err != nil {
|
|
t.Fatalf("pipeline-c1 must load for zh-ru: %v", err)
|
|
}
|
|
// ⚠ The zh fertility numbers are simultaneously the pair file's literals AND the generic fallback, so
|
|
// they cannot tell "the production pair layer is read" from "the production pair file is gone" — they only
|
|
// say the English file did not move them. The corridor is what discriminates: [2.2 4.2] exists nowhere
|
|
// but configs/pairs/zh-ru.yaml, so its absence would mean the zh pair layer stopped being read.
|
|
if zh.Segmentation.Fertility.Other != genericFallbackOther || zh.Segmentation.Fertility.CJK != 1.1978 {
|
|
t.Errorf("zh-ru fertility = %v/%v, want 1.1978/%v — the English pair file must not move the production pair",
|
|
zh.Segmentation.Fertility.CJK, zh.Segmentation.Fertility.Other, genericFallbackOther)
|
|
}
|
|
if got := zh.Gates.Coverage.LenRatio["zh-ru"]; len(got) != 2 || got[0] != 2.2 || got[1] != 4.2 {
|
|
t.Errorf("zh-ru corridor = %v, want [2.2 4.2] from configs/pairs/zh-ru.yaml — this is the one value of the production pair layer that is NOT also the engine fallback, so it is what proves the layer is still read", got)
|
|
}
|
|
}
|
|
|
|
// TestTheShippedPairsDeclareTheirBriefVocabulary pins what the DATA says, next to where the data lives:
|
|
// en-ru knows its own transcription system and zh-ru declares no vocabulary at all. The second half is
|
|
// not an omission — declaring one would give every Chinese book that states no transcription a new value
|
|
// on the wire, which is a move this pack owes the Chinese book not to make.
|
|
func TestTheShippedPairsDeclareTheirBriefVocabulary(t *testing.T) {
|
|
dir := filepath.Join("..", "..", "configs")
|
|
en, err := LoadPair(dir, "en-ru")
|
|
if err != nil || en == nil {
|
|
t.Fatalf("the shipped en-ru pair file must load: %v", err)
|
|
}
|
|
pol, ok := en.Brief["transcription"]
|
|
if !ok {
|
|
t.Fatal("en-ru must declare its transcription vocabulary — without it the operator template's `palladius` reaches an English book as an instruction")
|
|
}
|
|
if pol.Default != "practical" || len(pol.Allowed) != 1 || pol.Allowed[0] != "practical" {
|
|
t.Errorf("en-ru transcription policy = %+v, want practical as both the default and the only name", pol)
|
|
}
|
|
for _, name := range []string{"palladius", "polivanov"} {
|
|
if containsString(pol.Allowed, name) {
|
|
t.Errorf("%q is another pair's system and must not be a name en-ru accepts", name)
|
|
}
|
|
}
|
|
zh, err := LoadPair(dir, "zh-ru")
|
|
if err != nil || zh == nil {
|
|
t.Fatalf("the shipped zh-ru pair file must load: %v", err)
|
|
}
|
|
if len(zh.Brief) != 0 {
|
|
t.Errorf("zh-ru declares a brief vocabulary %v — this pack must not move the Chinese book, and a declared default reaches the wire of every book of the pair that states none", zh.Brief)
|
|
}
|
|
}
|