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 and complete local Actor/Home setup before submitting. For browser-only personal work, use the browser publication setup.

Install and activate Assessment in your project root:

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:

# 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.

ResponseAuthored content
choose-oneA list of choices with explicit {#id} values.
choose-manyThe same choice format, allowing multiple selections.
textA question heading and optional explanatory text.
essayA 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:

---

<!--
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, 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:

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

Include feedback below the question or in a later Block:

<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 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.

<!-- 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:

<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:

<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. 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:

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.