package pipeline import ( "encoding/json" "fmt" "os" "path/filepath" "sort" "strings" "testing" "textmachine/backend/internal/config" ) // promptlabel_test.go: `prompt_version` must track the BYTES of the prompt it labels. // // WHY THIS IS A GATE AND NOT A NORM. The norm already exists, written into the shipping config itself — // pipeline-c2.yaml: «лейбл обязан следовать за новым SHA файла» — and it was broken anyway: // prompts/zh-ru/editor.md was edited on 2026-08-01 while prompt_version stayed v3-discourse-reflow. The // cold run of 31.08 then nearly built a causal conclusion on comparing itself against a July bench // carrying that same label. Money was never at risk (PromptSHA256 folds into the snapshot, so the ENGINE // always knew); what was at risk is the COMPARABILITY of two runs, which is what an experiment is made of. // A rule that lives only in a comment inside a ratified decision, and is then skipped by the next ratified // decision, is a rule that needs a machine. // // WHY A REPO GATE AND NOT A RUNTIME CHECK. A runtime check can only compare a label against the payloads // THIS project database happens to hold, so it catches a label reused within one book. The incident was // BETWEEN books — a bench project and a fresh one, different databases — which is exactly the case a // runtime check cannot see. The repository is where both live, so the repository is where the pair is // pinned. It is also $0, snapshot-neutral, and it fails at CI time rather than after a purchase. // // UPDATING IT IS THE POINT, NOT AN OBSTACLE: a deliberate prompt edit is expected to come with a new // label, and `TM_UPDATE_PROMPT_LABELS=1 go test ./internal/pipeline/ -run TestPromptLabelsPinTheirBytes` // re-writes the ledger — the same shape as TM_UPDATE_GOLDEN. What must never happen silently is the third // case: the same label over different bytes. // promptLabelLedger is the checked-in memory: "//