91 lines
3 KiB
Go
91 lines
3 KiB
Go
package pipeline
|
||
|
||
import (
|
||
"context"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// allowshort_wire_test.go pins backlog 18 (D39.50 п.5) END TO END: an owner-SIGNED single-character term
|
||
// (蛊, 转 — the two the polygon found unreachable) must reach the MODEL when the seed says allow_short,
|
||
// and must stay unreachable without it. The bank-level override was already pinned (membank), but the
|
||
// finding was «не доезжают ни одним каналом», which is a statement about the whole path — seed file →
|
||
// materialization → selection → rendered injection → wire. The cold run's live signature relies on this
|
||
// path, so it is verified at $0 first.
|
||
|
||
const shortSeedAllowed = `
|
||
terms:
|
||
- src: 蛊
|
||
dst: гу
|
||
type: term
|
||
status: approved
|
||
allow_short: true
|
||
decl: { invariant: true, forms: ["гу"] }
|
||
`
|
||
|
||
const shortSeedPlain = `
|
||
terms:
|
||
- src: 蛊
|
||
dst: гу
|
||
type: term
|
||
status: approved
|
||
decl: { invariant: true, forms: ["гу"] }
|
||
`
|
||
|
||
// shortSource names 蛊 twice — nothing else in the chunk can produce the dst, so the rendering's presence
|
||
// on the wire is proof the key fired.
|
||
const shortSource = "方源看着蛊,那是一只月光蛊。"
|
||
|
||
func TestAllowShortReachesTheWire(t *testing.T) {
|
||
for _, c := range []struct {
|
||
name string
|
||
seed string
|
||
wantHit bool
|
||
}{
|
||
{"allow_short signs the single-char key through", shortSeedAllowed, true},
|
||
{"without it the single-key ban still holds", shortSeedPlain, false},
|
||
} {
|
||
t.Run(c.name, func(t *testing.T) {
|
||
rec := &reqRec{}
|
||
srv := newJSONProvider(rec, func(body string) (string, string) {
|
||
if isEditBody(body) {
|
||
return "Фан Юань смотрел на гу.", "stop"
|
||
}
|
||
return "Фан Юань смотрел на гу — лунный гу.", "stop"
|
||
})
|
||
defer srv.Close()
|
||
bookPath := setupProjectOpts(t, srv.URL, projectOpts{source: shortSource, glossarySeed: c.seed})
|
||
|
||
r := newRunner(t, bookPath)
|
||
defer r.Close()
|
||
if _, err := r.TranslateBook(context.Background()); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
msgs := bodyMessages(t, translatorBody(t, rec))
|
||
injected := false
|
||
for _, m := range msgs {
|
||
if m.Role == "system" && strings.Contains(m.Content, "蛊 → гу") {
|
||
injected = true
|
||
}
|
||
}
|
||
if injected != c.wantHit {
|
||
t.Fatalf("single-char key on the wire = %v, want %v; messages: %+v", injected, c.wantHit, msgs)
|
||
}
|
||
// The editor half of the same claim: a signed row is CANON for the bilingual editor, and the
|
||
// section it lands in is the signed one (backlog 19 — provenance, not match confidence).
|
||
for _, b := range rec.all() {
|
||
if !isEditBody(b) {
|
||
continue
|
||
}
|
||
em := bodyMessages(t, b)
|
||
got := strings.Contains(em[1].Content, "蛊 → «гу»")
|
||
if got != c.wantHit {
|
||
t.Fatalf("editor canon carries the short term = %v, want %v: %q", got, c.wantHit, em[1].Content)
|
||
}
|
||
if c.wantHit && strings.Contains(em[1].Content, "⟨проверить⟩") {
|
||
t.Fatalf("an owner-SIGNED row must not be rendered as unverified: %q", em[1].Content)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|