---
title: "S21 Feedback · Feedback"
description: "Contract, a board per state (full, low-confidence, achieved, playback, exemplar-pending, exemplar-failed, loading, empty, error, offline), tokens and strings."
source: "design/hifi/S21/screen.md"
---

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

# Hi-fi: S21 Feedback · Feedback

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

Stage: **hifi** · Key: `feedback/feedback` · Data-binding map: [bindings.md](/design/hifi/s21/bindings/index.md)

Drawn in the gallery: [Feedback](/design/gallery/index.html#g-feedback). Each board is the committed HTML in `screens/`, drawn on the example data in `docs/api/examples/`.

## Contract

- **full**: Summary → 4 dimensions (each with evidence) → one action (ink) → evidence → key points → model answer (labelled reference) → helpful?
- **low-confidence**: confidence = low: warning banner with confidence_note; a dimension without evidence shows 'not enough evidence' and does not lower the score; one action still shown.
- **achieved**: achieved_previous_action = true: 'You did it ✓' banner comes first; the new one-action moves to the next micro-skill.
- **playback**: Evidence row tapped: signed audio URL fetched, playback seeks to start_ms and stops at end_ms; row highlighted.
- **exemplar-pending**: TTS is async (voice per article language): exemplar.status = pending → skeleton + spinner; poll until ready.
- **exemplar-failed**: exemplar.status = failed: text fallback + retry; never blocks the second take.

Flows: F2 Daily quest.

Reads and calls:

- `GET /v1/attempts/{id} → assessment`
- `GET /v1/attempts/{id}/exemplar`
- `GET /v1/attempts/{id}/audio`
- `POST /v1/assessments/{id}/feedback {helpful, reason?}`

Local state:

- `local:player.state`
- `local:player.positionMs`

## Boards

One row per state. A state without boards of its own says what shows it.

| State | Board | Example data |
|---|---|---|
| full | [zh-Hans](/design/gallery/feedback/feedback--full.html) · [en](/design/gallery/feedback/feedback--full.en.html) | assessment-round1.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1.json) · [en](/design/examples/en/assessment-round1.json)), assessment-round1-achieved.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-achieved.json) · [en](/design/examples/en/assessment-round1-achieved.json)), assessment-round1-lowconf.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-lowconf.json) · [en](/design/examples/en/assessment-round1-lowconf.json)), exemplar-failed.json ([zh-Hans](/design/examples/zh-Hans/exemplar-failed.json) · [en](/design/examples/en/exemplar-failed.json)), exemplar-pending.json ([zh-Hans](/design/examples/zh-Hans/exemplar-pending.json) · [en](/design/examples/en/exemplar-pending.json)), exemplar-ready.json ([zh-Hans](/design/examples/zh-Hans/exemplar-ready.json) · [en](/design/examples/en/exemplar-ready.json)), article-long.json ([zh-Hans](/design/examples/zh-Hans/article-long.json) · [en](/design/examples/en/article-long.json)), article-product.json ([zh-Hans](/design/examples/zh-Hans/article-product.json) · [en](/design/examples/en/article-product.json)) |
| low-confidence | [zh-Hans](/design/gallery/feedback/feedback--low-confidence.html) · [en](/design/gallery/feedback/feedback--low-confidence.en.html) | assessment-round1.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1.json) · [en](/design/examples/en/assessment-round1.json)), assessment-round1-achieved.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-achieved.json) · [en](/design/examples/en/assessment-round1-achieved.json)), assessment-round1-lowconf.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-lowconf.json) · [en](/design/examples/en/assessment-round1-lowconf.json)), exemplar-failed.json ([zh-Hans](/design/examples/zh-Hans/exemplar-failed.json) · [en](/design/examples/en/exemplar-failed.json)), exemplar-pending.json ([zh-Hans](/design/examples/zh-Hans/exemplar-pending.json) · [en](/design/examples/en/exemplar-pending.json)), exemplar-ready.json ([zh-Hans](/design/examples/zh-Hans/exemplar-ready.json) · [en](/design/examples/en/exemplar-ready.json)), article-long.json ([zh-Hans](/design/examples/zh-Hans/article-long.json) · [en](/design/examples/en/article-long.json)), article-product.json ([zh-Hans](/design/examples/zh-Hans/article-product.json) · [en](/design/examples/en/article-product.json)) |
| achieved | [zh-Hans](/design/gallery/feedback/feedback--achieved.html) · [en](/design/gallery/feedback/feedback--achieved.en.html) | assessment-round1-achieved.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-achieved.json) · [en](/design/examples/en/assessment-round1-achieved.json)), exemplar-failed.json ([zh-Hans](/design/examples/zh-Hans/exemplar-failed.json) · [en](/design/examples/en/exemplar-failed.json)), exemplar-pending.json ([zh-Hans](/design/examples/zh-Hans/exemplar-pending.json) · [en](/design/examples/en/exemplar-pending.json)), exemplar-ready.json ([zh-Hans](/design/examples/zh-Hans/exemplar-ready.json) · [en](/design/examples/en/exemplar-ready.json)), article-long.json ([zh-Hans](/design/examples/zh-Hans/article-long.json) · [en](/design/examples/en/article-long.json)), article-product.json ([zh-Hans](/design/examples/zh-Hans/article-product.json) · [en](/design/examples/en/article-product.json)) |
| playback | [zh-Hans](/design/gallery/feedback/feedback--playback.html) · [en](/design/gallery/feedback/feedback--playback.en.html) | assessment-round1.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1.json) · [en](/design/examples/en/assessment-round1.json)), assessment-round1-achieved.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-achieved.json) · [en](/design/examples/en/assessment-round1-achieved.json)), assessment-round1-lowconf.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-lowconf.json) · [en](/design/examples/en/assessment-round1-lowconf.json)), exemplar-failed.json ([zh-Hans](/design/examples/zh-Hans/exemplar-failed.json) · [en](/design/examples/en/exemplar-failed.json)), exemplar-pending.json ([zh-Hans](/design/examples/zh-Hans/exemplar-pending.json) · [en](/design/examples/en/exemplar-pending.json)), exemplar-ready.json ([zh-Hans](/design/examples/zh-Hans/exemplar-ready.json) · [en](/design/examples/en/exemplar-ready.json)), article-long.json ([zh-Hans](/design/examples/zh-Hans/article-long.json) · [en](/design/examples/en/article-long.json)), article-product.json ([zh-Hans](/design/examples/zh-Hans/article-product.json) · [en](/design/examples/en/article-product.json)) |
| exemplar-pending | [zh-Hans](/design/gallery/feedback/feedback--exemplar-pending.html) · [en](/design/gallery/feedback/feedback--exemplar-pending.en.html) | assessment-round1.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1.json) · [en](/design/examples/en/assessment-round1.json)), assessment-round1-achieved.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-achieved.json) · [en](/design/examples/en/assessment-round1-achieved.json)), assessment-round1-lowconf.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-lowconf.json) · [en](/design/examples/en/assessment-round1-lowconf.json)), exemplar-pending.json ([zh-Hans](/design/examples/zh-Hans/exemplar-pending.json) · [en](/design/examples/en/exemplar-pending.json)), article-long.json ([zh-Hans](/design/examples/zh-Hans/article-long.json) · [en](/design/examples/en/article-long.json)), article-product.json ([zh-Hans](/design/examples/zh-Hans/article-product.json) · [en](/design/examples/en/article-product.json)) |
| exemplar-failed | [zh-Hans](/design/gallery/feedback/feedback--exemplar-failed.html) · [en](/design/gallery/feedback/feedback--exemplar-failed.en.html) | assessment-round1.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1.json) · [en](/design/examples/en/assessment-round1.json)), assessment-round1-achieved.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-achieved.json) · [en](/design/examples/en/assessment-round1-achieved.json)), assessment-round1-lowconf.json ([zh-Hans](/design/examples/zh-Hans/assessment-round1-lowconf.json) · [en](/design/examples/en/assessment-round1-lowconf.json)), exemplar-failed.json ([zh-Hans](/design/examples/zh-Hans/exemplar-failed.json) · [en](/design/examples/en/exemplar-failed.json)), article-long.json ([zh-Hans](/design/examples/zh-Hans/article-long.json) · [en](/design/examples/en/article-long.json)), article-product.json ([zh-Hans](/design/examples/zh-Hans/article-product.json) · [en](/design/examples/en/article-product.json)) |
| loading | [no board of its own](/design/hifi/s21/bindings/index.md#states): From [states.md](/design/states/index.md) (Feedback): not reachable before `assessed` |  |
| empty | [no board of its own](/design/hifi/s21/bindings/index.md#states): From [states.md](/design/states/index.md) (Feedback): — |  |
| error | [no board of its own](/design/hifi/s21/bindings/index.md#states): 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 | [no board of its own](/design/hifi/s21/bindings/index.md#states): From [states.md](/design/states/index.md) (Feedback): cached assessment; playback & exemplar disabled with "needs network" |  |

### The boards

Each state as drawn (393 × 852), one board per locale. Open a board on its own for its spec panel.

**full**

[S21 full · zh-Hans](/design/gallery/feedback/feedback--full.html) [S21 full · en](/design/gallery/feedback/feedback--full.en.html)

**low-confidence**

[S21 low-confidence · zh-Hans](/design/gallery/feedback/feedback--low-confidence.html) [S21 low-confidence · en](/design/gallery/feedback/feedback--low-confidence.en.html)

**achieved**

[S21 achieved · zh-Hans](/design/gallery/feedback/feedback--achieved.html) [S21 achieved · en](/design/gallery/feedback/feedback--achieved.en.html)

**playback**

[S21 playback · zh-Hans](/design/gallery/feedback/feedback--playback.html) [S21 playback · en](/design/gallery/feedback/feedback--playback.en.html)

**exemplar-pending**

[S21 exemplar-pending · zh-Hans](/design/gallery/feedback/feedback--exemplar-pending.html) [S21 exemplar-pending · en](/design/gallery/feedback/feedback--exemplar-pending.en.html)

**exemplar-failed**

[S21 exemplar-failed · zh-Hans](/design/gallery/feedback/feedback--exemplar-failed.html) [S21 exemplar-failed · en](/design/gallery/feedback/feedback--exemplar-failed.en.html)

## Tokens used

By path in `../../system/tokens.source.json`.

| Token | Where |
|---|---|
| `color.accentPrimary` | `.btn--primary` |
| `color.accentPrimaryPressed` | `.btn--primary` |
| `color.bandBasic` | `inline` |
| `color.bandClear` | `inline` |
| `color.bgCanvas` | `.device`, `.dock`, `.navbar`, `.screen` |
| `color.bgInverse` | `.one-action`, `.pbtn`, `.player` |
| `color.bgInverseRaised` | `.icon-btn`, `.oa-example`, `.one-action`, `.skel` … |
| `color.bgSunken` | `.btn`, `.card--sunken`, `.dim-bar`, `.dim-row` … |
| `color.bgSurface` | `.btn--secondary`, `.card`, `.list`, `inline` |
| `color.dimEfficiency` | `inline` |
| `color.dimFluency` | `inline` |
| `color.dimKeyInfo` | `inline` |
| `color.dimStructure` | `inline` |
| `color.lineHairline` | `.btn--secondary`, `.btn--sm`, `.dim-row`, `.evidence` … |
| `color.lineStrong` | `.btn--secondary`, `.player`, `.tag--line`, `.track` |
| `color.reward` | `.oa-head`, `.one-action`, `inline` |
| `color.statusInfoSoft` | `.banner--info` |
| `color.statusSuccess` | `.banner--success`, `.c-success` |
| `color.statusSuccessSoft` | `.banner--success` |
| `color.statusWarning` | `.banner--warning`, `.c-warning` |
| `color.statusWarningSoft` | `.banner--warning` |
| `color.textDisabled` | `.btn` |
| `color.textOnAccent` | `.btn--primary` |
| `color.textOnInverse` | `.icon-btn`, `.oa-example`, `.one-action`, `.pbtn` … |
| `color.textOnInverseSecondary` | `.c-on-inverse-2` |
| `color.textPrimary` | `.banner--info`, `.banner--success`, `.banner--warning`, `.btn--secondary` … |
| `color.textSecondary` | `.c-secondary`, `.tag` |
| `color.textTertiary` | `.c-tertiary`, `.list-row`, `.score-ring`, `.step-count` … |
| `color.topicViolet` | `.evidence`, `.is-playing`, `.ts-chip` |
| `color.topicVioletSoft` | `.evidence`, `.is-playing` |
| `radius.button` | `.btn` |
| `radius.card` | `.card` |
| `radius.lg` | `.one-action` |
| `radius.md` | `.card--md`, `.list` |
| `radius.pill` | `.btn--sm` |
| `radius.sm` | `.banner`, `.oa-example`, `.one-action` |
| `radius.xs` | `.tag` |
| `space.gutter` | `.dock`, `.navbar`, `.pad`, `.section-head` |
| `space.s3` | `.section-head` |
| `space.s5` | `.card` |
| `space.s6` | `.screen` |
| `space.safeBottom` | `.dock`, `.has-dock`, `.screen` |
| `space.safeTop` | `.device`, `.screen` |
| `space.section` | `.section-head` |
| `space.sizeCtaHeight` | `.btn`, `.has-dock`, `.screen` |
| `space.sizeHitMin` | `.icon-btn` |
| `space.sizeNavbarHeight` | `.navbar` |
| `space.sizeTabbarHeight` | `.screen` |
| `typography.callout` | `.t-callout` |
| `typography.caption1` | `.t-caption` |
| `typography.footnote` | `.t-footnote` |
| `typography.headline` | `.t-headline` |
| `typography.subheadline` | `.t-subhead` |
| `typography.title3` | `.t-title3` |

## Strings

`app.name`, `band.basic`, `band.clear`, `common.back`, `common.retry`, `common.step_of.a11y`, `diag.result.ring_label`, `dimension.efficiency`, `dimension.fluency`, `dimension.insufficient`, `dimension.key_info`, `dimension.structure`, `dimension.weights`, `feedback.achieved`, `feedback.confidence.high`, `feedback.confidence.low`, `feedback.cta`, `feedback.dims.title`, `feedback.evidence.hint`, `feedback.evidence.pause.a11y`, `feedback.evidence.title`, `feedback.exemplar.failed`, `feedback.exemplar.intro`, `feedback.exemplar.pending`, `feedback.exemplar.play.a11y`, `feedback.exemplar.tag`, `feedback.exemplar.title`, `feedback.helpful.no.a11y`, `feedback.helpful.title`, `feedback.helpful.yes.a11y`, `feedback.keypoints.count`, `feedback.keypoints.title`, `feedback.low_confidence`, `feedback.meta`, `feedback.nav`, `feedback.not_achieved`, `feedback.one_action.basis`, `feedback.one_action.listen`, `feedback.ring_label`, `home.greeting.format`, `home.quest.focus.last`, `micro.conclusion_first`, `micro.three_points`, `notif.daily.title`, `onboarding.progress.a11y`, `paywall.calendar.rest`, `paywall.projection.score`, `processing.nav.round1`

## Notes for the app tracks

Motion, haptics, Dynamic Type and VoiceOver: [engagement.md](/design/engagement/index.md), [tokens.md](/design/tokens/index.md) §6–7 and
[ios-handoff.md](/design/ios-handoff/index.md). Open a board with `?theme=dark&dt=1.35&binds=1` to see dark mode, the largest
tested type size and every bound element.

Tracking-plan events: no tracking plan page exists yet; ADR-001 D12 names the events.

Tokens with no group in `system/tokens.source.json` yet (they stay in [tokens.css](/design/tokens.css)): `--dt`, `--elevation-1`, `--elevation-2`, `--fill`, `--font-family-numeric`, `--font-family-reading`, `--font-family-text`, `--font-weight-bold`, `--font-weight-medium`, `--font-weight-regular`, `--font-weight-semibold`, `--motion-duration-countup`, `--motion-duration-fast`, `--motion-duration-instant`, `--motion-duration-slow`, `--motion-ease-emphasized`, `--motion-ease-standard`.
