package eval import "time" // Story is a STAR+R interview prep story extracted from Block F. type Story struct { Title string `json:"title"` Situation string `json:"situation"` Task string `json:"task"` Action string `json:"action"` Result string `json:"result"` Reflection string `json:"reflection,omitempty"` } // LegitimacyTier is the Block-G verdict. Written to applications.legitimacy // and reports.legitimacy for filtering and UI coloring. type LegitimacyTier string const ( TierHigh LegitimacyTier = "high" TierCaution LegitimacyTier = "caution" TierSuspicious LegitimacyTier = "suspicious" TierUnknown LegitimacyTier = "unknown" ) // ParseTier maps the Claude-emitted tier label to the canonical enum. // Returns TierUnknown for unrecognized values so callers can default safely. func ParseTier(s string) LegitimacyTier { switch s { case "High Confidence", "high confidence", "High", "high": return TierHigh case "Proceed with Caution", "proceed with caution", "Caution", "caution": return TierCaution case "Suspicious", "suspicious": return TierSuspicious default: return TierUnknown } } // Evaluation is the parsed output of a single A-G eval. Blocks are kept as // raw markdown so the TUI + report renderer can display them verbatim. type Evaluation struct { Archetype string Score float64 Legitimacy LegitimacyTier BlockA string BlockB string BlockC string BlockD string BlockE string BlockF string BlockG string Stories []Story // structured STAR stories extracted from BlockF Raw string // full concatenated markdown, in case blocks didn't parse cleanly ElapsedMS int64 // time spent in Claude CLI ReceivedAt time.Time // wall clock at completion } // JobContext is what the runner passes into the eval prompt. Kept separate from // the full store.Job so tests don't need the DB. type JobContext struct { URL string Company string Title string Location string Source string JDText string // raw job description text (scraped or fetched elsewhere) }