# Build the "Context inventory" pattern: `ContextInventory`

## 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 visible list of what the model can see right now — files, memories, tools, prior turns.

Use it when: Anywhere output quality depends on context the user cannot otherwise inspect.

## What to build
A panel listing exactly what was assembled into the model's context for a given answer: instructions, tools, files, memories and prior turns, with sizes, what was cut, and how full the window was. It lets a person drop items or ask for fuller inclusion and then re-run. It renders as a popover from a context meter or as a side panel.

### Props
- `items`: Array<{ id: string; kind: "system" | "tools" | "file" | "memory" | "history" | "tool-result" | "other"; title: string; detail?: string; tokens: number; inclusion: "full" | "truncated" | "dropped"; truncation?: { included: string; omitted: string; omittedTokens: number }; removable?: boolean }>, the context as the runtime actually assembled it.
- `capacity`: { window: number; reservedForReply: number }, the total window and the part kept free for the answer.
- `forResponse`: { id: string; assembledAt: Date }, which answer this inventory describes.
- `status`: "current" | "stale" | "loading" | "unavailable", controlled by the parent.
- `pendingChanges?`: Array<{ id: string; deltaTokens: number }>, removals or inclusions queued for the next run.
- `onRemove(id)`, `onIncludeFull(id)`, `onSummarize?(id)` and `onRerun()`: callbacks. The component never changes the context itself.
- `formatTokens?`: (n: number) => string, defaults to "18.4K".

### States it must render
- Current: a capacity bar segmented by item, the list with each item's size, and the space left ("0.3K free").
- Truncated item: marked "Truncated" with what got in and what was cut in plain words ("Pages 1–4 of 9 fit; sections 5–9 cut"), plus Include all and its token cost.
- No room: Include all is disabled with the shortfall ("Needs 21.6K, 0.3K free") and the largest removable items offered as ways to free space.
- Stale: after changes, a banner says the shown answer used the old context, with Re-run.
- Loading: skeleton rows. Unavailable: "Context wasn't reported for this answer"; never a guessed or intended list.

### Interactions
- Remove queues the item, previews the new bar and free space, and calls `onRemove`.
- Include all and Summarize call their callbacks; the bar previews the change before Re-run.
- Re-run calls `onRerun`; clicking a bar segment moves focus to its row.

### Edge cases
- An item the person attached but the runtime dropped appears with `inclusion` "dropped" and 0 tokens, so "I attached it" never reads as "the model saw it".
- Items the person didn't add (tool results, system instructions) are still listed; system items are not removable.
- Many small items of one kind group into one row ("14 files, 9.2K") that expands.
- Reported totals exceed the window: show the overflow as a warning rather than clipping the bar silently.

## Must avoid
A context window the user cannot inspect, leaving them to guess why the answer went sideways.

## Engineering constraint
Report actual assembled context, including truncation, not the intended set.

## Accessibility
- The capacity bar has a text equivalent ("111.7K of 112K used"); segments are not the only way to read sizes.
- Announce the new free-space figure when a change is queued.

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