---
title: "S21 bindings"
description: "Data-binding map of Feedback · Feedback: every field to its source, and what each required state shows."
source: "design/hifi/S21/bindings.md"
---

> Part of [Brand and design](/design/llms.txt). Every page: [llms.txt](/llms.txt).

# Data-binding map: S21 Feedback · Feedback

> Generated by `botgumi-design index` from `../../screens.json`. Edit that file, not this page.

Every field [S21](/design/hifi/s21/index.md) shows and where it comes from.

| Field | Source (endpoint or local state) | Format | Fallback |
|---|---|---|---|
| "You did it ✓" | `api GET /attempts/{attempt_id} assessment.achieved_previous_action` · `assessment.achieved_previous_action = true` + `previous_action` → micro-skill title | success banner, first element | — |
| "You did it ✓" | `api GET /attempts/{attempt_id} assessment.previous_action` |  |  |
| "not yet" line | `api GET /attempts/{attempt_id} assessment.achieved_previous_action` · `achieved_previous_action = false` | neutral row | hidden when null |
| low-confidence | `api GET /attempts/{attempt_id} assessment.confidence` · `assessment.confidence = low` + `confidence_note` (article language) | warning banner | generic sentence |
| low-confidence | `api GET /attempts/{attempt_id} assessment.confidence_note` |  |  |
| score ring | `api GET /attempts/{attempt_id} assessment.overall` · `assessment.overall`, `band` (colour), `band_label` (Accept-Language) | 104pt ring | — |
| score ring | `api GET /attempts/{attempt_id} assessment.band` |  |  |
| score ring | `api GET /attempts/{attempt_id} assessment.band_label` |  |  |
| summary | `api GET /attempts/{attempt_id} assessment.summary` · `assessment.summary` (article language) | title3 | — |
| dimension name | `api GET /attempts/{attempt_id} assessment.dimensions` · `dimension.<key>` client key (or API label) | — | — |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.key_info.note` · `assessment.dimensions.<key>.note / score / evidence_ids[0] → evidence.start_ms` | `mm:ss` chip | `insufficient_evidence` → `dimension.insufficient` |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.key_info.score` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.key_info.evidence_ids[]` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.structure.note` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.structure.score` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.structure.evidence_ids[]` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.efficiency.note` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.efficiency.score` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.efficiency.evidence_ids[]` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.fluency.note` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.fluency.score` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.dimensions.fluency.evidence_ids[]` |  |  |
| dimension note / score / evidence chip | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` |  |  |
| one action | `api GET /attempts/{attempt_id} assessment.one_action.title` · `assessment.one_action.title / instruction / example_sentence / evidence_id` (article language) | ink card | — |
| one action | `api GET /attempts/{attempt_id} assessment.one_action.instruction` |  |  |
| one action | `api GET /attempts/{attempt_id} assessment.one_action.example_sentence` |  |  |
| one action | `api GET /attempts/{attempt_id} assessment.one_action.evidence_id` |  |  |
| evidence list | `api GET /attempts/{attempt_id} assessment.evidence[]` · `assessment.evidence[]` sorted by `start_ms` | quote + note | — |
| evidence list | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` |  |  |
| playback | `api GET /attempts/{id}/audio url` · `GET /v1/attempts/{id}/audio → url (15-min TTL)`, `local:player.positionMs` | seek `start_ms`, stop `end_ms` | 410 → `feedback.evidence.expired` |
| playback | `local player.positionMs` |  |  |
| key points | `api GET /attempts/{attempt_id} assessment.key_point_coverage[]` · `assessment.key_point_coverage[]` (article language) | count `derived:` | hide |
| exemplar | `api GET /attempts/{attempt_id}/exemplar status` · `exemplar.status / text / duration_ms / label` (label Accept-Language; text + voice in article language) | pending skeleton / ready player / failed text + retry | `unavailable` → hide section |
| exemplar | `api GET /attempts/{attempt_id}/exemplar text` |  |  |
| exemplar | `api GET /attempts/{attempt_id}/exemplar duration_ms` |  |  |
| exemplar | `api GET /attempts/{attempt_id}/exemplar label` |  |  |
| meta | `api GET /attempts/{attempt_id} assessment.rubric_version` · `assessment.rubric_version`, `model_ref`, `confidence` | caption | — |
| meta | `api GET /attempts/{attempt_id} assessment.model_ref` |  |  |
| meta | `api GET /attempts/{attempt_id} assessment.confidence` |  |  |
| helpful | `call POST /assessments/{id}/feedback` · `POST /v1/assessments/{id}/feedback {helpful, reason?}` | thumbs; 👎 opens reason sheet | queued offline |
| `GET /v1/attempts/{id}/audio → url; local:player.positionMs` | `call GET /attempts/{id}/audio` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `GET /v1/attempts/{id}/exemplar → status` | `api GET /attempts/{id}/exemplar status` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.achieved_previous_action + previous_action` | `api GET /attempts/{attempt_id} assessment.achieved_previous_action` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.achieved_previous_action + previous_action` | `api GET /attempts/{attempt_id} assessment.previous_action` |  |  |
| `assessment.achieved_previous_action = false` | `api GET /attempts/{attempt_id} assessment.achieved_previous_action` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.band_label (Accept-Language)` | `api GET /attempts/{attempt_id} assessment.band_label` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.confidence + confidence_note` | `api GET /attempts/{attempt_id} assessment.confidence` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.confidence + confidence_note` | `api GET /attempts/{attempt_id} assessment.confidence_note` |  |  |
| `assessment.dimensions.efficiency.note` | `api GET /attempts/{attempt_id} assessment.dimensions.efficiency.note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.dimensions.efficiency.score` | `api GET /attempts/{attempt_id} assessment.dimensions.efficiency.score` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.dimensions.fluency.note` | `api GET /attempts/{attempt_id} assessment.dimensions.fluency.note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.dimensions.fluency.score` | `api GET /attempts/{attempt_id} assessment.dimensions.fluency.score` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.dimensions.key_info.note` | `api GET /attempts/{attempt_id} assessment.dimensions.key_info.note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.dimensions.key_info.score` | `api GET /attempts/{attempt_id} assessment.dimensions.key_info.score` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.dimensions.structure.note` | `api GET /attempts/{attempt_id} assessment.dimensions.structure.note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.dimensions.structure.score` | `api GET /attempts/{attempt_id} assessment.dimensions.structure.score` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[0].note` | `api GET /attempts/{attempt_id} assessment.evidence[].note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[0].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[0].transcript_excerpt` | `api GET /attempts/{attempt_id} assessment.evidence[].transcript_excerpt` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[1].note` | `api GET /attempts/{attempt_id} assessment.evidence[].note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[1].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[1].transcript_excerpt` | `api GET /attempts/{attempt_id} assessment.evidence[].transcript_excerpt` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[2].note` | `api GET /attempts/{attempt_id} assessment.evidence[].note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[2].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[2].transcript_excerpt` | `api GET /attempts/{attempt_id} assessment.evidence[].transcript_excerpt` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[3].note` | `api GET /attempts/{attempt_id} assessment.evidence[].note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[3].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[3].transcript_excerpt` | `api GET /attempts/{attempt_id} assessment.evidence[].transcript_excerpt` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[4].note` | `api GET /attempts/{attempt_id} assessment.evidence[].note` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[4].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[4].transcript_excerpt` | `api GET /attempts/{attempt_id} assessment.evidence[].transcript_excerpt` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[id=ev_1].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[id=ev_2].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[id=ev_3].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[id=ev_5].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.evidence[id=ev_a1].start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.key_point_coverage[0].text` | `api GET /attempts/{attempt_id} assessment.key_point_coverage[].text` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.key_point_coverage[1].text` | `api GET /attempts/{attempt_id} assessment.key_point_coverage[].text` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.key_point_coverage[2].text` | `api GET /attempts/{attempt_id} assessment.key_point_coverage[].text` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.one_action.evidence_id → evidence.start_ms` | `api GET /attempts/{attempt_id} assessment.one_action.evidence_id` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.one_action.evidence_id → evidence.start_ms` | `api GET /attempts/{attempt_id} assessment.evidence[].start_ms` |  |  |
| `assessment.one_action.example_sentence` | `api GET /attempts/{attempt_id} assessment.one_action.example_sentence` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.one_action.instruction` | `api GET /attempts/{attempt_id} assessment.one_action.instruction` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.one_action.micro_skill_id` | `api GET /attempts/{attempt_id} assessment.one_action.micro_skill_id` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.rubric_version + model_ref + confidence` | `api GET /attempts/{attempt_id} assessment.rubric_version` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `assessment.rubric_version + model_ref + confidence` | `api GET /attempts/{attempt_id} assessment.model_ref` |  |  |
| `assessment.rubric_version + model_ref + confidence` | `api GET /attempts/{attempt_id} assessment.confidence` |  |  |
| `assessment.summary (article language)` | `api GET /attempts/{attempt_id} assessment.summary` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `derived: count(key_point_coverage.covered)` | `derived key_points_covered` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `exemplar.duration_ms` | `api GET /attempts/{attempt_id}/exemplar duration_ms` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `exemplar.label` | `api GET /attempts/{attempt_id}/exemplar label` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `exemplar.status = failed` | `api GET /attempts/{attempt_id}/exemplar status` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `exemplar.status = pending` | `api GET /attempts/{attempt_id}/exemplar status` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `exemplar.text` | `api GET /attempts/{attempt_id}/exemplar text` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `session.stage = round2` | `api GET /sessions/{session_id} stage` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |
| `session.stage → derived step` | `api GET /sessions/{session_id} stage` · From the board's `data-bind`; no row in data-binding.md yet. |  |  |

## Derived values

Computed on device; each from the sources it names.

| Value | From | How |
|---|---|---|
| `key_points_covered` | `api GET /attempts/{attempt_id} assessment.key_point_coverage[].covered` | How many key points the retelling covered. |

## Binds on the boards

The `data-bind` values across every state.

- `GET /v1/attempts/{id}/audio → url; local:player.positionMs`
- `GET /v1/attempts/{id}/exemplar → status`
- `POST /v1/assessments/{id}/feedback`
- `assessment.achieved_previous_action + previous_action`
- `assessment.achieved_previous_action = false`
- `assessment.band_label (Accept-Language)`
- `assessment.confidence + confidence_note`
- `assessment.dimensions.efficiency.note`
- `assessment.dimensions.efficiency.score`
- `assessment.dimensions.fluency.note`
- `assessment.dimensions.fluency.score`
- `assessment.dimensions.key_info.note`
- `assessment.dimensions.key_info.score`
- `assessment.dimensions.structure.note`
- `assessment.dimensions.structure.score`
- `assessment.evidence[0].note`
- `assessment.evidence[0].start_ms`
- `assessment.evidence[0].transcript_excerpt`
- `assessment.evidence[1].note`
- `assessment.evidence[1].start_ms`
- `assessment.evidence[1].transcript_excerpt`
- `assessment.evidence[2].note`
- `assessment.evidence[2].start_ms`
- `assessment.evidence[2].transcript_excerpt`
- `assessment.evidence[3].note`
- `assessment.evidence[3].start_ms`
- `assessment.evidence[3].transcript_excerpt`
- `assessment.evidence[4].note`
- `assessment.evidence[4].start_ms`
- `assessment.evidence[4].transcript_excerpt`
- `assessment.evidence[id=ev_1].start_ms`
- `assessment.evidence[id=ev_2].start_ms`
- `assessment.evidence[id=ev_3].start_ms`
- `assessment.evidence[id=ev_5].start_ms`
- `assessment.evidence[id=ev_a1].start_ms`
- `assessment.key_point_coverage[0].text`
- `assessment.key_point_coverage[1].text`
- `assessment.key_point_coverage[2].text`
- `assessment.one_action.evidence_id → evidence.start_ms`
- `assessment.one_action.example_sentence`
- `assessment.one_action.instruction`
- `assessment.one_action.micro_skill_id`
- `assessment.one_action.title`
- `assessment.overall`
- `assessment.rubric_version + model_ref + confidence`
- `assessment.summary (article language)`
- `derived: count(key_point_coverage.covered)`
- `exemplar.duration_ms`
- `exemplar.label`
- `exemplar.status = failed`
- `exemplar.status = pending`
- `exemplar.text`
- `session.stage = round2`
- `session.stage → derived step`

## States

- Loading: From [states.md](/design/states/index.md) (Feedback): not reachable before `assessed`
- Empty: From [states.md](/design/states/index.md) (Feedback): —
- Error (retryable / not): From [states.md](/design/states/index.md) (Feedback): exemplar [feedback--exemplar-failed](/design/gallery/feedback/feedback--exemplar-failed.html); audio URL failure → toast · fatal: —
- Offline: From [states.md](/design/states/index.md) (Feedback): cached assessment; playback & exemplar disabled with "needs network"
