textmachine/backend/internal/config/genre_retired_test.go

79 lines
3 KiB
Go

package config
import (
"os"
"path/filepath"
"testing"
)
// genre_retired_test.go: `genre:` is retired (owner 16.08 «просто выкидываем», D39.138 п.2в). The field
// left the API contract and the intake form in batch 0.3.0; it now leaves the engine — no prompt renders
// it and the brief canon no longer folds it.
//
// TWO HALVES AND THEY PULL OPPOSITE WAYS, which is why both are pinned here. The key must still LOAD,
// because the platform writes a book's book.yaml once from an operator template it carries through unread
// and never rewrites — a strict decoder that refused the line would refuse books already on disk, mid-run.
// And the VALUE must reach nothing: a book that differs only in its genre is now the same brief, so the
// two books' hashes are equal and neither is re-billed for a word nobody reads.
func TestARetiredGenreKeyStillLoadsAndReachesNothing(t *testing.T) {
load := func(extra string) *Book {
t.Helper()
dir := t.TempDir()
b, err := LoadBook(writeBook(t, dir, extra))
if err != nil {
t.Fatalf("book with %q must load: %v", extra, err)
}
return b
}
withGenre := load("genre: ранобэ\n")
otherGenre := load("genre: производственный роман\n")
without := load("")
// The brief is what a re-purchase is priced against, so this equality IS the money statement: an
// operator template that still carries the line costs its book nothing, and neither does editing it.
if withGenre.BriefHash() != without.BriefHash() {
t.Errorf("a declared genre still moves the brief: %s vs %s", withGenre.BriefHash(), without.BriefHash())
}
if withGenre.BriefHash() != otherGenre.BriefHash() {
t.Errorf("two genres are still two briefs: %s vs %s", withGenre.BriefHash(), otherGenre.BriefHash())
}
}
// TestNoShippingPromptAsksForTheGenre is the other end of the same removal, and it is a repo gate rather
// than a runtime one for the reason the prompt-label ledger is: the renderer already refuses an unknown
// {{…}} marker loudly, but only for a pair whose prompts somebody actually runs. A pack authored later
// with the placeholder should be caught by the repository that retired it, not by a paid run.
func TestNoShippingPromptAsksForTheGenre(t *testing.T) {
root := filepath.Join("..", "..", "prompts")
var offenders []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() {
return err
}
body, rerr := os.ReadFile(path)
if rerr != nil {
return rerr
}
if len(body) > 0 && containsGenrePlaceholder(string(body)) {
offenders = append(offenders, path)
}
return nil
})
if err != nil {
t.Fatalf("walk %s: %v", root, err)
}
if len(offenders) > 0 {
t.Fatalf("the genre placeholder is retired and the renderer no longer supplies it — these prompts would fail loud on their first render: %v", offenders)
}
}
func containsGenrePlaceholder(s string) bool {
const marker = "{{genre}}"
for i := 0; i+len(marker) <= len(s); i++ {
if s[i:i+len(marker)] == marker {
return true
}
}
return false
}