# Build the "Memory manager" pattern: `MemoryManager`

## 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 browsable store of remembered facts and preferences, each editable and deletable.

Use it when: Assistants used daily, where accumulated memory becomes both the value and the risk.

## What to build
A browsable list of what an assistant remembers, searchable and filterable by category, with each memory's source and where it was last used. A person can correct a single memory in place or delete it on its own. It renders in settings or a side panel.

### Props
- `memories`: Array<{ id: string; text: string; category: string; source: { label: string; at: Date }; lastUsed?: { label: string; at: Date; responseId?: string }; expiresAt?: Date }>.
- `categories`: string[], with `category` and `onCategoryChange(c: string)` for controlled filtering ("All" included).
- `query`: string and `onQueryChange(q: string)`, controlled search.
- `editingId?`: string and `savingId?`: string, which row is being edited or saved.
- `recentlyDeleted?`: { id: string; text: string }, drives the undo row.
- `status`: "loading" | "ready" | "error".
- `onEdit(id: string, text: string)`, `onDelete(id: string)`, `onUndoDelete(id: string)` and `onOpenUsage?(responseId: string)`: callbacks. The component never writes memory itself.
- `onClearAll?()`: optional and secondary, behind a confirmation; it is never the only way to remove something.

### States it must render
- Ready: a count header, category chips with counts, and rows showing text, category, source and date, with Edit and Delete on each.
- Editing: the row becomes an input with Save and Cancel; Save is disabled while the text is empty.
- Deleted: the row is replaced by "Deleted. Undo" for a few seconds before it leaves.
- Last used: a row can show the answer that used it ("Used yesterday in renewal prep"), so a bad answer can be traced to the memory behind it.
- No matches: "No memories match" with a clear-filters action. Empty: explains what kinds of things will appear here.
- Loading and error: skeleton rows; an error message with Retry.

### Interactions
- Typing filters live; chips filter by category and combine with the search.
- Edit swaps the row for an input and focuses it; Enter saves via `onEdit`, Escape cancels.
- Delete calls `onDelete` immediately and shows Undo; Undo calls `onUndoDelete`.
- The last-used link calls `onOpenUsage` with the response id.

### Edge cases
- Editing a memory that was used recently: after saving, note "Earlier answers used the old value" next to the usage link.
- Two memories that contradict each other (e.g. two seat counts): both stay visible and adjacent when searched, so the person picks which to keep.
- A memory with an expiry shows it ("expires 5 Oct") so temporary facts aren't mistaken for permanent ones.
- Hundreds of memories: group by category and paginate or virtualise; counts stay accurate.

## Must avoid
Memory as an opaque black box with only a nuclear "clear all" option.

## Engineering constraint
Memory writes are user-visible events; make retrieval attributable so you can debug bad recall.

## Accessibility
- After a delete, focus moves to the Undo control, then to the next row when it disappears.
- Announce result counts politely as filters change ("4 memories").

## 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.
