## Summary
Three fixes to the playground RAG answer path. (1) Each playground agent call (answer, selection, planner) opens a LangSmith run with usage and cost, filterable by document key. (2) The selection agent built its model only from `ANTHROPIC_AUTH_TOKEN`, which the hosted task does not have, so it never ran there and every hosted answer came from fused similarity order alone; it now uses the same credential resolver as the answer model. (3) The routes prepend a document identity block (Title, Issuer, Form, Period from the documents row) to the user message on every answer path, because a chart on a supplement slide carries no date and the answer model refused to date it. System prompt unchanged.

## Related Jira Issue
**Jira**: [QUE-366](https://mandeng.atlassian.net/browse/QUE-366)

## Acceptance Criteria - Functional Evidence

### ✅ AC1: Playground agent calls land in LangSmith with usage and cost, filterable by document

**Real Example: LangSmith project `quber-dev`, queried via `/runs/query` on 2026-09-08 and 2026-09-09**

Runs named `answer_declared`, `answer_fixed`, `select_chunks`, and `resolve_row` are present with `prompt_tokens`, `completion_tokens`, `total_cost`, and metadata `doc_key`.

```text
Aggregate for one document (doc_key 998c8ed06c0be22d, 93 questions):
answer_declared  runs=93  input=2,124,206  output=21,907  cost=$11.17
select_chunks    runs=93  input=3,814,782  output=4,210   cost=$3.84
```

**Results:**

- ✓ Runs present for the answer, selection, and planner paths, each with `prompt_tokens`, `completion_tokens`, and `total_cost`
- ✓ Every run carries `doc_key` in metadata, so runs filter by document
- ✓ 93 questions on one document → 93 `answer_declared` runs and 93 `select_chunks` runs, $15.01 combined

**Production Data Tested:**

- Document `998c8ed06c0be22d`: 93 questions → 186 traced runs (93 answer, 93 selection)

---

### ✅ AC2: With only `ANTHROPIC_API_KEY` set, retrieval runs the selection agent

**Real Example: In-process call of the `/api/chat` route against the hosted RDS, 2026-09-08 21:39 local, env `ANTHROPIC_AUTH_TOKEN=` (blank) and `ANTHROPIC_API_KEY` from SSM**

```text
credentials: auth_token set = False | api_key set = True
selection model class: AnthropicModel
doc 291: shape=scalar answer='4.0x' refs=['fv-95'] retrieved=10
doc 290: shape=scalar answer='631,478' refs=['t2-18-1', 't27-4-1'] retrieved=10
selection fallback warnings: 0
```

Before the fix, CloudWatch log group `/quber/playground` showed 283 lines `selection agent failed (ANTHROPIC_AUTH_TOKEN not set); falling back to fused order` on 2026-09-08.

**Results:**

- ✓ Selection model builds as `AnthropicModel` with the API key alone, no auth token
- ✓ 0 selection fallback warnings across both documents
- ✓ Measured effect with selection on, 558 sweep questions across six KREF filings, Opus 5: 49 questions unanswerable → answered, 8 answered → unanswerable
- ✓ Cited source in context slot 1 for 90% of answers, versus 40% with fused order

**Production Data Tested:**

- Document 291 (hosted RDS): answer `4.0x`, refs `['fv-95']`, 10 chunks retrieved
- Document 290 (hosted RDS): answer `631,478`, refs `['t2-18-1', 't27-4-1']`, 10 chunks retrieved
- Six KREF filings, 558 sweep questions → 49 gained, 8 lost

---

### ✅ AC3: Every answer path opens the user prompt with the document identity block

**Real Example: Same run as AC2, first lines of the user prompt built by `declared.prompt_for` for both documents**

```text
Document
  Title:  Q1 2026 Earnings Supplement
  Issuer:  KREF
  Form:  99-2
  Period:  Q1 2026
Every figure in the context below is from this document unless a chunk states another period.

Context chunks:
```

Unit tests in `tests/playground/test_document.py` cover the header fields, omitted fields, the no-document case, and that the declared, fixed, and grounded prompt builders all open with the block.

**Results:**

- ✓ Block present at the top of the user prompt on the live route for both documents
- ✓ Measured effect at full 10-chunk context, same contexts run with and without the block: +6 answers on the Q1 2026 supplement (charts now dated), 0 losses attributable to the block
- ✓ Without the block, 21 chart-sourced answers across the supplements were declined for lack of a period label
- ✓ 5 unit tests cover header fields, omitted fields, no-document case, and all three prompt builders

**Production Data Tested:**

- KREF Q1 2026 Earnings Supplement (Form 99-2): +6 answers with the block, 0 losses
- KREF supplements: 21 chart-sourced answers declined without the block

---

### ✅ AC4: The transcript no longer shows the list of retrieved chunks under an answer

**Real Example: Commit `349b9ce`, `src/quber/playground/ui/src/chat.jsx` and the rebuilt `src/quber/playground/static/app.js`**

```text
chat.jsx: RetrievedChunks import and render commented out with a note;
          the component and the `retrieved` field in the chat payload are unchanged
static/app.js: grep -c "Retrieved N chunks" -> 0
```

**Results:**

- ✓ Rebuilt `static/app.js` contains no "Retrieved N chunks" string (grep count 0)
- ✓ `RetrievedChunks` component retained and the `retrieved` field still present in the chat payload
- ✓ Gates: oxlint Passed, prettier check Passed, compiled output up to date Passed
- ✓ `tests/playground`: 110 passed

**Production Data Tested:**

- `src/quber/playground/static/app.js` (compiled from `chat.jsx`): "Retrieved N chunks" occurrences → 0

---

## Test Evidence

- ✅ `uv run pytest -q` → PASS, 700 passed, 12 warnings in 20.41s
- ✅ `uv run pytest tests/playground -q` → PASS, 110 passed, 5 warnings in 13.33s
- ✅ `uv run pre-commit run --files src/quber/playground/selection.py src/quber/playground/agent.py src/quber/playground/app.py src/quber/playground/answers/document.py src/quber/playground/answers/declared.py src/quber/playground/answers/fixed.py src/quber/playground/answers/streaming.py src/quber/playground/answers/expectation.py tests/playground/test_document.py` → PASS: ruff Passed, ruff-format Passed, pyright type checking Passed
- Coverage: not run for this PR

## Changes Made

Commits on the branch: `11d7013`, `5283ca2`, `e6394af`, `349b9ce`.

- `src/quber/playground/tracing.py` (earlier commits on this branch): shared LangSmith tracer and `document_key` contextvar; each agent call site opens its own run.
- `src/quber/playground/selection.py`: model built via `quber.playground.agent.anthropic_model`; OAuth-only requirement removed.
- `src/quber/playground/answers/document.py` (new): `DocumentIdentity.from_row` / `header()`, `with_document()`.
- `src/quber/playground/answers/declared.py`, `fixed.py`, `streaming.py`, `expectation.py`, `src/quber/playground/agent.py`: optional `document` parameter threaded through every answer path; prompt builders prepend the block.
- `src/quber/playground/app.py`: chat, chat stream, and batch routes build `DocumentIdentity` from the document row and pass it.
- `tests/playground/test_document.py` (new): 5 tests.
- `src/quber/playground/ui/src/chat.jsx` and `src/quber/playground/static/app.js`: retrieved-chunks panel not drawn (commented out, component retained).

https://claude.ai/code/session_012MrxUTZDhTxkbPXnUu5ZXN
