[@layout]: ../docs.layout.md

# Assessment

Turn Markdown question Blocks into response forms. Assessment describes the
questions and evaluation; Core Input owns drafts and submissions.

---

## Install and configure

Use an initialized [Quickstart project](../start/first-site.guide.md) and complete
[local Actor/Home setup](../accounts/auth.reference.md#local-actor) before submitting.
For browser-only personal work, use the [browser publication setup](../extend/state.reference.md#save-input-and-progress-in-the-browser).

Install and activate Assessment in your project root:

```sh
bun run pmx plugins add assessment
```

The stock preset connects Assessment to Input: question authoring becomes Input
fields and submissions record Assessment results. No repository Plugin or other
TypeScript configuration is required. Use a repository Plugin only when adding
custom response types, evaluators, or completion composition.

---

## Author questions

Create `paths/check-in.assessment.md`:

```md
# Contrast check-in

---

<!--
id: contrast
type: question
response: choose-one
required: true
-->

## Which pair has stronger contrast?

- Black and white {#strong}
- Two similar grays {#weak}
```

Open `/check-in.assessment` with `bun run pmx dev`. Assessment supplies the
choice controls and a submit button. Keep question and option ids stable: saved
responses refer to those ids.

| Response | Authored content |
| --- | --- |
| `choose-one` | A list of choices with explicit `{#id}` values. |
| `choose-many` | The same choice format, allowing multiple selections. |
| `text` | A question heading and optional explanatory text. |
| `essay` | A question heading and optional explanatory text, with a multiline response. |

Use a separate Block for each question. `required: true` requires a response
before submission. Run `bun run pmx lint` to check the question model.

---

## Try the other response types

Append these Blocks to `paths/check-in.assessment.md` and reload the same route:

```md
---

<!--
id: useful-changes
type: question
response: choose-many
required: true
-->

## Which changes would help a reader?

- Increase contrast {#contrast}
- Add descriptive links {#links}
- Remove every heading {#headings}

---

<!--
id: title
type: question
response: text
required: true
-->

## Give your redesign a title

---

<!--
id: explanation
type: question
response: essay
required: true
-->

## Explain one choice

Describe how your change helps someone reading on a phone.
```

The first Block allows multiple selections, the second a short answer, and the
third a multiline explanation. Complete and submit each response, then reload
to verify its saved values. These questions collect responses without automatic
correct-answer scoring.

---

## Save personal responses

Sign in as Ada using the [local account setup](../accounts/auth.reference.md#local-actor),
choose an answer on `/check-in.assessment`, and submit. Reload: the submitted
response remains associated with Ada. Editing a choice creates a draft; submit
again to replace the saved result. Another Actor has separate responses.

If submission is unavailable, supply all required answers and check the admitted
Actor, Home, and server write access. Production requires configured credentials
and persistent writable hosting. Ordinary static exports cannot accept submissions;
a browser publication saves locally and does not send answers to a teacher.

---

## Check answers

Add an answer id and optional feedback to a choice question's topmatter:

```yaml
answer: strong
feedback: Black and white have a greater difference in luminance.
```

Include feedback below the question or in a later Block:

```md
<x-assessment-feedback question="contrast" />
```

Each Question keeps its own response under its Block id. A survey’s generated
submit control uses `blocks="*"` to save its active Question responses together.
The answers and resulting Assessment attempt commit in one transaction; a failed
validation or grading result commits neither. A question excluded by `when:` keeps
its saved answer but contributes no current Block output.

Assessment determines active Questions with the same Block evaluator used by
normal rendering. Conditions can depend on earlier or later Block outputs,
including outputs computed by another Plugin; cyclic dependencies are rejected.
A guided survey with conditional Questions needs an unconditional final Block for
its generated submit control. Custom host clients can [evaluate drafts through a
View](../extend/views.reference.md#evaluate-block-outputs) without saving.

The submit control becomes **Check answers** when evaluation is configured.
Feedback reflects submitted answers; editing a draft does not change the last
submitted result until the next check.

---

## Use Question outputs in your report

An evaluated Question exposes saved grading through ordinary Block outputs. For
`id: contrast`, `$contrast.contrast` is its answer, `$contrast.correct` is the saved
correctness result, and `$contrast.feedback` is feedback when supplied.
`$contrast.result` contains the complete validated evaluator result, including any
custom evaluator details.

```md
<!-- id: report -->

## Your report

Your choice: {{ $contrast.contrast ?? "Not submitted" }}

Correct: {{ $contrast.correct ?? "Not checked" }}

{{ $contrast.feedback ?? "Check your answer to see feedback." }}
```

These references also work in component properties and Block `when:` conditions.
No result component is required. Grading outputs are absent until a saved check;
`false` means an incorrect checked answer. Draft edits do not change saved grading.
Inactive Questions retain their saved answers but contribute no current Block output.
Field names contributed by different Plugins must be unambiguous.

Report components accept the same values as any other component:

```html
<x-report-stat label="Correct answer" value="{{ $contrast.correct }}" total="1" />
```

For aggregate reports, let a scoring Block export numbers or rows, then bind those
outputs normally. A row is an object of string, number, boolean or null values:

```html
<x-report-table rows="{{ $scores.rows }}" columns="label,points" />
<x-report-chart type="bar" rows="{{ $scores.rows }}" label="Scores"
  category="label" value="points" min="0" max="10" />
```

These examples assume a Block named `scores` exports `rows`. A whole property
binding preserves the array, including when passed through a literate component.
Chart bounds are explicit. Reports have no separate field registry or state store;
the producing Block owns the data. Missing values show an unavailable result.

Named Source instances keep independent answers, saved checks and completion for
the same Actor. Replaying a submission in one instance cannot reuse another
instance's attempt.

---

## Compose progress

The factory also supplies `assessment.completion`, a derived provider for
[Completion](./completion.reference.md). To include it, install
`@pathmx/completion@beta` and create `plugins/assessment.plugin.ts`. This
repository preset replaces the stock Assessment and Input instances while
retaining package activation:

```ts
import { createAssessmentPlugin } from "@pathmx/assessment"
import { createCompletionPlugin } from "@pathmx/completion"
import { definePreset } from "@pathmx/core"
import { createInputPlugin } from "@pathmx/core/plugins"

const assessment = createAssessmentPlugin()
const input = createInputPlugin({
  authoring: [assessment.input],
  submissions: [assessment.submission],
})
const completion = createCompletionPlugin({
  storage: "actor",
  derived: [assessment.completion],
})

export default definePreset([
  input.plugin,
  assessment.plugin,
  completion.plugin,
])
```

Ordinary assessments contribute a submission requirement. Their submitted
state determines completion; correct-answer scoring is a separate result.
Render `<x-completion-progress />` or `<x-completion-outline />` where readers
need to see progress.
