# Build the "AI identity: name and persona" pattern: `PersonaConfigurator`

## Stack (edit this block to match your project)
- React 18+ with TypeScript: one function component, typed props, no `any`.
- Tailwind CSS, using your design system's tokens if you have them.
- Presentational only: data comes in through props, decisions go out through callbacks. No fetching or global state inside.
- If your codebase already has conventions (naming, shared components, tokens), follow them over this spec.

## What the pattern is for
A deliberate name, voice and character for the AI, setting expectations before any output arrives.

Use it when: Any assistant users will address directly and repeatedly.

## What to build
An admin panel for setting the assistant's name, label and voice, with a live preview of sample replies and a check that blocks persona choices that overclaim. The persona is edited and versioned separately from task instructions. It renders in product or workspace settings.

### Props
- `persona`: { name: string; label: string; avatarUrl?: string; tone: string; description: string; version: number }, the current draft; `label` is the always-visible disclosure, e.g. "AI agent".
- `toneOptions`: Array<{ id: string; label: string; description: string }>, the voices on offer, e.g. Plain, Warm.
- `previews`: Array<{ prompt: string; reply: string }>, sample exchanges rendered in the current voice (supplied by the parent).
- `issues`: Array<{ id: string; severity: "block" | "warn"; message: string; excerpt?: string }>, results of the overclaim check, e.g. claims of feelings, being human or guaranteed outcomes.
- `publishedVersion?`: number and `status`: "draft" | "checking" | "publishing" | "published" | "error".
- `onChange(persona)`, `onPublish()` and `onRevert(version: number)`: callbacks. The component never generates text itself.

### States it must render
- Draft: name, label, tone and description fields, with a preview showing how the name and label appear in a chat header plus sample replies.
- Checking: preview dimmed with "Checking wording"; Publish disabled.
- Blocked: issues listed above the Publish button with the offending excerpt highlighted in the preview (e.g. "I promise I'll fix this", "I'm so happy to help!" as a feelings claim); Publish disabled until fixed.
- Warnings only: Publish enabled, warnings visible with a short explanation each.
- Published: "Version 4 is live" with the date and a Revert to previous version action.

### Interactions
- Changing tone or name calls `onChange`; the preview updates from the new `previews` prop.
- Clicking an issue scrolls to and highlights the excerpt in the preview.
- Publish calls `onPublish` only when there are no `block` issues and `label` is non-empty.
- The version selector shows history and calls `onRevert` after a confirm.

### Edge cases
- Empty or removed AI label: blocking issue, since the persona must always disclose it is an AI.
- A human-sounding name (a first name with no label): allowed, but the label must render next to it everywhere in the preview.
- Unpublished draft differs from live: show "Unpublished changes" and a diff of changed fields.
- Very long names: cap at a set length and show how it truncates in the chat header preview.

## Must avoid
A cute persona that overpromises competence, or claims of feeling that mislead about what it is.

## Engineering constraint
Keep persona in a versioned system prompt separate from task instructions so it can be tuned alone.

## Accessibility
- The issues list is announced when it changes after a check; each issue links to its excerpt with a focusable target.
- Tone options are a radio group with their descriptions as accessible descriptions.

## House rules
- Real `<button>`/`<input>` elements, full keyboard use, visible focus; announce status changes with `aria-live="polite"`; respect `prefers-reduced-motion`.
- All user-facing text comes from props (or a `labels` prop) so it can be translated.
- One consistent accent marks anything the AI made or is doing; amber means "needs a person", red means risky, green means done. Never rely on colour alone.
- Fits a 360 px wide container without horizontal scrolling.

## Acceptance checks
- [ ] Every state above can be rendered by passing props, with no internal fake data.
- [ ] Every interaction and edge case above behaves as described.
- [ ] Nothing in "Must avoid" can happen with this component.

## Deliver
1. The component file with its exported prop types.
2. A short usage example that renders each state.
