Files
Maven/internal/phraser/eval/templates_test.go
T
kami 13e5170e9e Hand-written Russian nudge templates plus a picker
Nudge wording as data instead of generation. The wording lives in
internal/phraser/nudges_ru_v1.json (embedded), about 10 variants per rule:
water, meal, break, service_down, netdata_critical, routine:, morning:, plus
a contentless default. That JSON is long because it is data — the owner can
edit any line of Russian without touching Go.

The picker:
- random, but never the same variant twice in a row for the same rule
- deterministic when seeded (math/rand with an injectable source)
- fills {since} / {service} / {what} from the candidate, and skips any variant
  whose value is missing, so no raw placeholder can reach the piper voice
- {since} is spelled out in words ("полтора часа", "семь часов"), because
  "3 ч" is wrong in a Russian voice

Scores 15/15 on the existing nudge fixture, on every seed swept. Nothing is
wired yet — that is the next commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
2026-07-31 18:18:55 +04:00

59 lines
1.7 KiB
Go

package eval
import (
"context"
"math/rand"
"testing"
"github.com/kami/maven/internal/phraser"
)
// TestTemplateNudges scores the hand-written Russian templates on the same
// fixture the model is scored on. No model, no network — it runs in milliseconds.
//
// The bar is every case, not most of them: the templates are hand-written, so a
// failure is a bug in one line of Russian, not model variance.
func TestTemplateNudges(t *testing.T) {
f, err := Load()
if err != nil {
t.Fatalf("Load: %v", err)
}
// Fixed seed: the score must not depend on which variant came up.
nt, err := phraser.NewNudgeTemplates(rand.NewSource(20260731))
if err != nil {
t.Fatalf("NewNudgeTemplates: %v", err)
}
rep, err := Score(context.Background(), "ru templates", nt, f)
if err != nil {
t.Fatalf("Score: %v", err)
}
t.Log("\n" + rep.String())
t.Log("\n" + rep.Messages())
if rep.Passed != rep.Total {
t.Errorf("templates scored %d/%d, want every case:\n%s",
rep.Passed, rep.Total, rep.Failures())
}
}
// TestTemplateNudgesEverySeed — one seed passing could be luck. Every variant of
// every rule has to pass every check, so sweep seeds until each has been used.
func TestTemplateNudgesEverySeed(t *testing.T) {
f, err := Load()
if err != nil {
t.Fatalf("Load: %v", err)
}
for seed := int64(0); seed < 60; seed++ {
nt, err := phraser.NewNudgeTemplates(rand.NewSource(seed))
if err != nil {
t.Fatalf("NewNudgeTemplates: %v", err)
}
rep, err := Score(context.Background(), "ru templates", nt, f)
if err != nil {
t.Fatalf("Score: %v", err)
}
if rep.Passed != rep.Total {
t.Errorf("seed %d: %d/%d\n%s", seed, rep.Passed, rep.Total, rep.Failures())
}
}
}