97 lines
4.2 KiB
Go
97 lines
4.2 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// promptlabel_pair_test.go: a pair labels its OWN prompts.
|
|
//
|
|
// ⛔ WHY THIS IS A MONEY PIN AND NOT TIDINESS. `prompt_version` folds into the snapshot, and a run config
|
|
// is pair-agnostic: one string in pipeline-c1.yaml labels the translator prompt of EVERY pair that config
|
|
// serves. Before this key, a pack that edited one pair's prompts had two ways to go and both were wrong —
|
|
// bump the shared label and re-snapshot (re-buy) the books of the pairs whose bytes never moved, or leave
|
|
// it and let one label stand over two different texts, which is exactly what the label ledger exists to
|
|
// catch. The third way is this file's subject.
|
|
|
|
// TestAPairLabelsItsOwnPromptsWithoutMovingAnother is the live proof on the SHIPPING files, not a fixture:
|
|
// the same run config, read for two pairs, must give the English prompts the pair's own label and leave
|
|
// the Chinese ones on the run config's.
|
|
func TestAPairLabelsItsOwnPromptsWithoutMovingAnother(t *testing.T) {
|
|
models, err := LoadModels(filepath.Join("..", "..", "configs", "models.yaml"))
|
|
if err != nil {
|
|
t.Fatalf("load models: %v", err)
|
|
}
|
|
cfg := filepath.Join("..", "..", "configs", "pipeline-c1.yaml")
|
|
labels := func(pair string) map[string]string {
|
|
t.Helper()
|
|
p, err := LoadPipeline(cfg, models, pair, nil)
|
|
if err != nil {
|
|
t.Fatalf("pipeline-c1 must load for %s: %v", pair, err)
|
|
}
|
|
out := map[string]string{}
|
|
for _, st := range p.Stages {
|
|
out[st.Name] = st.PromptVersion
|
|
}
|
|
return out
|
|
}
|
|
en, zh := labels("en-ru"), labels("zh-ru")
|
|
if len(en) == 0 || len(zh) == 0 {
|
|
t.Fatal("premise broken: the shipping config resolved no stages, so nothing below is about labels")
|
|
}
|
|
// The RUN CONFIG's own literal, read from the file rather than copied here — a copy would keep passing
|
|
// after somebody edited the config, which is the exact class of staleness this whole ledger is about.
|
|
raw, err := os.ReadFile(cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(raw), "prompt_version: "+zh["draft"]) {
|
|
t.Errorf("the zh-ru draft label %q is not the one pipeline-c1.yaml states — a pair that declares no label of its own must keep the run config's", zh["draft"])
|
|
}
|
|
if en["draft"] == zh["draft"] {
|
|
t.Errorf("both pairs' draft stages carry %q, so the en-ru prompt edit either did not happen or is riding the Chinese book's label — the pair layer's prompt_versions is what keeps them apart", en["draft"])
|
|
}
|
|
if en["edit"] == zh["edit"] {
|
|
t.Errorf("both pairs' edit stages carry %q; the same reasoning as the draft stage applies", en["edit"])
|
|
}
|
|
}
|
|
|
|
// TestAPairLabelKeyHasToNameAPromptFile pins the refusals. An empty label is the dangerous one: the stage
|
|
// check that demands a label has already passed by the time the pair layer is applied, so an empty value
|
|
// would REPLACE a stated label with nothing and the run would carry no comparability statement at all.
|
|
func TestAPairLabelKeyHasToNameAPromptFile(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.MkdirAll(filepath.Join(dir, "pairs"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
write := func(body string) {
|
|
t.Helper()
|
|
if err := os.WriteFile(filepath.Join(dir, "pairs", "xx-yy.yaml"), []byte(body), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
// PREMISE: a well-formed declaration loads and carries the label, or the refusals below would be
|
|
// indistinguishable from "this key does nothing at all".
|
|
write("pair: xx-yy\nprompt_versions:\n translator: v1-xx\n")
|
|
pc, err := LoadPair(dir, "xx-yy")
|
|
if err != nil || pc == nil {
|
|
t.Fatalf("a well-formed pair label must load: %v", err)
|
|
}
|
|
if pc.PromptVersions["translator"] != "v1-xx" {
|
|
t.Fatalf("the label must reach the pair config, got %+v", pc.PromptVersions)
|
|
}
|
|
for _, bad := range []struct{ name, body string }{
|
|
{"a path instead of a base name", "pair: xx-yy\nprompt_versions:\n ../translator: v1\n"},
|
|
{"a separator in the key", "pair: xx-yy\nprompt_versions:\n en-ru/translator: v1\n"},
|
|
{"an empty label", "pair: xx-yy\nprompt_versions:\n translator: \" \"\n"},
|
|
} {
|
|
t.Run(bad.name, func(t *testing.T) {
|
|
write(bad.body)
|
|
if _, err := LoadPair(dir, "xx-yy"); err == nil {
|
|
t.Error("must fail loud at load — a label nobody can resolve is not a smaller statement, it is a missing one")
|
|
}
|
|
})
|
|
}
|
|
}
|