# User feedback mechanism exists on AI responses

- **Pattern:** `ab-000336` (`ai-ux-patterns.feedback-control.feedback-mechanism`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000336
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000336)

## Why it matters

Without thumbs-up/thumbs-down on responses, you have no signal for which prompts work, which models regress, or which system-prompt edits break more than they fix. Every serious AI product uses this feedback stream to drive eval sets, fine-tuning data, and regression detection — shipping without it means flying blind on quality. The pain compounds over time: by the time users complain loudly enough to file a ticket, the bad behavior has been in production for weeks.

## Severity rationale

Critical because it is the primary quality signal for a probabilistic system; its absence blocks iteration.

## Remediation

Add thumbs-up and thumbs-down buttons to every assistant message. Each click should POST `{messageId, rating, conversationId}` to a feedback endpoint that persists to a `message_feedback` table keyed by message id. Optionally open a dialog on thumbs-down to collect a freeform reason. Implement the route at `app/api/messages/feedback/route.ts`.

```tsx
await fetch('/api/messages/feedback', { method: 'POST', body: JSON.stringify({ messageId, rating: 'up' }) })
```

## Detection

- **ID:** `feedback-mechanism`
- **Severity:** `critical`
- **What to look for:** Count all AI response message components. For each, enumerate the feedback controls present: thumbs-up/thumbs-down, star ratings, "Was this helpful?", report/flag buttons. Verify each control has a click handler that sends feedback data to an API route (e.g., `app/api/feedback/route.ts`, `/api/rate`, `POST /messages/:id/feedback`). Check whether the feedback data is persisted to a database. A feedback icon with no wired handler does not count as pass — do not pass based on decorative UI elements.
- **Pass criteria:** At least 1 binary positive/negative feedback control (thumbs up/down, helpful/not helpful) is present on AI response messages and the feedback is transmitted to the backend. Report the count even on pass: "X of Y response components have feedback controls."
- **Fail criteria:** No feedback controls on AI responses. User has no way to signal response quality.
- **Skip (N/A) when:** Same as `regeneration-button`.
- **Detail on fail:** `"No feedback controls (thumbs, ratings, flag) found on AI response message components. No feedback API route detected."`.
- **Remediation:** Feedback loops are how you learn whether your AI is actually working. Without them, you're flying blind.

  ```tsx
  const handleFeedback = async (messageId: string, rating: 'up' | 'down') => {
    await fetch('/api/messages/feedback', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ messageId, rating }),
    })
    setFeedbackGiven(prev => ({ ...prev, [messageId]: rating }))
  }

  {message.role === 'assistant' && (
    <div className="flex gap-2 mt-2">
      <button
        onClick={() => handleFeedback(message.id, 'up')}
        aria-label="Good response"
        className={feedbackGiven[message.id] === 'up' ? 'text-green-600' : 'text-muted-foreground'}
      >
        <ThumbsUpIcon className="w-4 h-4" />
      </button>
      <button
        onClick={() => handleFeedback(message.id, 'down')}
        aria-label="Bad response"
        className={feedbackGiven[message.id] === 'down' ? 'text-red-600' : 'text-muted-foreground'}
      >
        <ThumbsDownIcon className="w-4 h-4" />
      </button>
    </div>
  )}
  ```

---

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-000336
