# `TypeSafeAPI.Question.Score`
[🔗](https://github.com/typesend/typesafe_ai/blob/v0.1.0-alpha.3/lib/typesafe_api/question/score.ex#L1)

Rate the state along an ordered scale you describe in steps.

    TypeSafeAPI.score("How frustrated is the customer?", ["Calm", "Frustrated", "Very angry"])

TypeSafe's advice: ask for one snap judgment per question, and write the
levels in order from low to high; this library enforces two at minimum and
ten at most as local policy (see "Limits" below).

`levels` is an ordered list from the low end of the scale to the high end.
This library requires at least two levels and caps a Score at ten: a single
level cannot produce a meaningful score, and the live API rejects eleven
levels with a 400 (see `DESIGN.md`). Each level is a description: a string,
or a map or list when a level needs structure.

A level may also be given as `{label, description}`. The label is a short
name you want back in the answer (`TypeSafeAPI.Answer.Score.label`), and the
pair is sent to the API as a structured level:

    {"Very angry", "Threats to cancel, profanity, all caps"}
    #=> {"label": "Very angry", "description": "Threats to cancel, ..."}

The same structured shape written out by hand,
`%{"label" => "Very angry", "description" => "..."}`, is recognized as a
labelled level too, so a level that round-trips through the wire `legend`
still reports its label rather than an `inspect/1` of the map.

Labels are strings. Atom labels — `[calm: "...", angry: "..."]`, the shape
`TypeSafeAPI.choice/2` takes — are not accepted yet; write the label as a
string for now.

Every level has a string label in the answer. A plain string level is its
own label; a structured level without one gets a truncated `inspect/1` of
itself, which is fine for logs but not for display, so give structured
levels a label when the label matters. Labels must be distinct and non-empty:
the answer's `levels` list is keyed by label, so two levels sharing one name
cannot be told apart.

## Limits

| limit      | our validator | spec (`priv/openapi.json`, API 0.2.0)  | source |
| ---------- | -------------- | ---------------------------------------- | ------ |
| min levels | 2              | `minItems: 1`                            | local policy: a one-level score is meaningless |
| max levels | 10             | no bound                                  | local policy, matching a live-API 400 observed at 11 (see `DESIGN.md`) |

`ScoreQuestion.criteria` in the OpenAPI spec requires only `minItems: 1` and
sets no maximum; both bounds here are this library's own policy, tighter
than what the spec itself requires.

# `level`

```elixir
@type level() ::
  TypeSafeAPI.Question.description()
  | {String.t(), TypeSafeAPI.Question.description()}
```

# `t`

```elixir
@type t() :: %TypeSafeAPI.Question.Score{
  instructions: TypeSafeAPI.Question.instructions(),
  levels: [level()]
}
```

# `description`

```elixir
@spec description(level()) :: TypeSafeAPI.Question.description()
```

The description sent to the API for a level, without any label wrapper.

# `label`

```elixir
@spec label(level()) :: String.t()
```

The string label for a level: the label of a `{label, description}` pair or
of a `%{"label" => ...}` map, a string level itself, or a truncated
`inspect/1` of any other structured level.

# `new`

```elixir
@spec new(TypeSafeAPI.Question.instructions(), [level()]) :: t()
```

Builds a Score question.

`instructions` is optional and may be `nil`; only the levels are required.

# `wire_type`

```elixir
@spec wire_type() :: String.t()
```

The `type` tag this question and its answer carry on the wire.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
