hsa-app/internal/classify/prompt_test.go
Jean-Michel Tremblay c715c8e0c0
All checks were successful
Build and Test / build-and-test (push) Successful in 37s
AI classifier correction notes + misread review (AI tab)
Add a global, temporal ai_notes list appended to the classifier prompt
(seeded once from no-PII defaults, documented in README), managed inline
on a new AI tab with a read-only view of the assembled prompt. Every
AI-run upload records the browser-round-tripped suggestion blob + model;
misreads are derived (final field != AI guess) and reviewed one by one
(image + per-field guess-vs-entered + notes-since), attributing which
note fixed each or closing unresolved. Update SPEC (new section 10),
DESIGN item 15, README, and changelog (0.0.3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:04:30 -04:00

90 lines
2.6 KiB
Go

package classify
import (
"strings"
"testing"
"maisym.com/hsa/internal/config"
)
func contains(list []string, want string) bool {
for _, s := range list {
if s == want {
return true
}
}
return false
}
// The Tremblay family: Jean-Michel and Jude share the initial "J", so neither may
// get a bare "J. Tremblay" variant; Alex ("A") and Evan ("E") are unique and may.
func TestNameVariantsAmbiguousInitial(t *testing.T) {
all := []config.Person{
{First: "Jean-Michel", Last: "Tremblay"},
{First: "Jude", Last: "Tremblay"},
{First: "Alex", Last: "Tremblay"},
{First: "Evan", Last: "Tremblay"},
{First: "Lynna", Last: "Nguyen"},
}
jm := NameVariants(all[0], all)
if contains(jm, "J. Tremblay") || contains(jm, "Tremblay, J.") {
t.Errorf("Jean-Michel must not get an ambiguous single-initial variant: %v", jm)
}
// Compound initials are unique to Jean-Michel and should appear.
if !contains(jm, "J-M Tremblay") {
t.Errorf("Jean-Michel should get compound initial variant J-M Tremblay: %v", jm)
}
jude := NameVariants(all[1], all)
if contains(jude, "J. Tremblay") {
t.Errorf("Jude must not get an ambiguous single-initial variant: %v", jude)
}
alex := NameVariants(all[2], all)
if !contains(alex, "A. Tremblay") {
t.Errorf("Alex (unique initial) should get A. Tremblay: %v", alex)
}
// Lynna's surname is unique, so a single initial is fine.
lynna := NameVariants(all[4], all)
if !contains(lynna, "L. Nguyen") {
t.Errorf("Lynna (unique surname) should get L. Nguyen: %v", lynna)
}
// Order/comma variants are always present and unambiguous.
for _, want := range []string{"Jean-Michel Tremblay", "Tremblay Jean-Michel", "Tremblay, Jean-Michel"} {
if !contains(jm, want) {
t.Errorf("expected variant %q in %v", want, jm)
}
}
}
func TestBuildSystemPrompt(t *testing.T) {
persons := []config.Person{
{First: "Jean-Michel", Last: "Tremblay"},
{First: "Lynna", Last: "Nguyen"},
}
categories := []config.Category{
{Name: "Pharmacy", Examples: []string{"CVS", "Rx"}},
{Name: "Other"},
}
p := BuildSystemPrompt(persons, categories, "2026-06-17", []string{"Treat handwritten totals as authoritative."})
for _, want := range []string{
"Jean-Michel Tremblay", // canonical label
"Lynna Nguyen",
"Pharmacy",
"CVS", // example injected
"2026-06-17", // today
"AMBIGUOUS", // the ambiguity rule
"IGNORE everyone", // ignore-other-people rule
"null", // unknown handling
"raw_name", // raw echo
"CLOSEST to today", // date tie-breaker
} {
if !strings.Contains(p, want) {
t.Errorf("system prompt missing %q", want)
}
}
}