package store import ( "context" "database/sql" "errors" "time" "github.com/google/uuid" "github.com/jmoiron/sqlx" ) type Verdict struct { ID string `db:"id" json:"id"` TopicID string `db:"topic_id" json:"topic_id"` JudgeAgentID string `db:"judge_agent_id" json:"judge_agent_id"` VerdictJSON []byte `db:"verdict_json" json:"-"` // surface raw via Render Rationale string `db:"rationale" json:"rationale"` TokensInput int `db:"tokens_input" json:"tokens_input"` TokensOutput int `db:"tokens_output" json:"tokens_output"` ProducedAt time.Time `db:"produced_at" json:"produced_at"` } type VerdictStore struct { db *sqlx.DB } func NewVerdictStore(db *sqlx.DB) *VerdictStore { return &VerdictStore{db: db} } type SubmitVerdictInput struct { TopicID string JudgeAgentID string VerdictJSON []byte Rationale string TokensInput int TokensOutput int } // Submit writes the (one-and-only) verdict for a topic. Unique constraint // on topic_id means a second submission returns a duplicate-key error; // caller surfaces that as 409. func (s *VerdictStore) Submit(ctx context.Context, in SubmitVerdictInput) (*Verdict, error) { id := uuid.NewString() if _, err := s.db.ExecContext(ctx, `INSERT INTO verdicts (id, topic_id, judge_agent_id, verdict_json, rationale, tokens_input, tokens_output) VALUES (?, ?, ?, ?, ?, ?, ?)`, id, in.TopicID, in.JudgeAgentID, in.VerdictJSON, in.Rationale, in.TokensInput, in.TokensOutput); err != nil { return nil, err } return s.GetByTopic(ctx, in.TopicID) } func (s *VerdictStore) GetByTopic(ctx context.Context, topicID string) (*Verdict, error) { var v Verdict err := s.db.GetContext(ctx, &v, `SELECT * FROM verdicts WHERE topic_id = ?`, topicID) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } if err != nil { return nil, err } return &v, nil }