Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ A fifth language-learning exercise idea surfaced a gap the existing "extra
text" fields do not cover: `hint` is shown on demand before/during answering,
`examples` are worked examples shown before answering that must not spoil it,
and neither fits "explain the French word-order rule AFTER the learner
answers". `Exercise` gains an optional `explanation` (Markdown, max 1000
chars, mirrors `hint`'s shape) - not restricted to any exercise type, like
`hint` itself.
answers". `Exercise` gains an optional `explanation` (Markdown, max 2000
chars - twice `hint`'s 1000, since Markdown structure eats characters
faster than a single-line nudge) - not restricted to any exercise type,
like `hint` itself.

`x-schema-version` `1.12` -> `1.13` in both schemas (lesson + content-manifest
move in lockstep, established convention). Additive: content without the new
Expand Down
2 changes: 1 addition & 1 deletion docs/lesson-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ see [Stable identity](#stable-identity-stable_id)).

### Explanation (post-answer)

`explanation` (string \| null, max 1000 chars, schema v1.13) is Markdown
`explanation` (string \| null, max 2000 chars, schema v1.13) is Markdown
explaining WHY the answer/grammar is what it is - a French word-order rule, a
grammatical case, a spelling exception. Timing is what distinguishes it from
the other three "extra text" fields:
Expand Down
4 changes: 2 additions & 2 deletions schema/lesson.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -412,15 +412,15 @@
"explanation": {
"anyOf": [
{
"maxLength": 1000,
"maxLength": 2000,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional Markdown explanation of WHY the answer/grammar is what it is (e.g. word order, a grammatical case), shown AFTER the learner answers - regardless of correct or incorrect - unlike ``hint`` (on demand, before/during answering) and ``examples`` (worked examples shown before answering, must not spoil it). Not restricted to any exercise type. Additive; schema_version 1.13.",
"description": "Optional Markdown explanation of WHY the answer/grammar is what it is (e.g. word order, a grammatical case), shown AFTER the learner answers - regardless of correct or incorrect - unlike ``hint`` (on demand, before/during answering) and ``examples`` (worked examples shown before answering, must not spoil it). 2000 chars, twice ``hint``'s 1000: Markdown structure (a short list, bold terms) eats characters faster than a single-line nudge, and a real \"why\" often runs longer than a hint. Not restricted to any exercise type. Additive; schema_version 1.13.",
"title": "Explanation"
},
"ext_payload": {
Expand Down
4 changes: 2 additions & 2 deletions src/__fixtures__/schema-baseline/lesson.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -412,15 +412,15 @@
"explanation": {
"anyOf": [
{
"maxLength": 1000,
"maxLength": 2000,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional Markdown explanation of WHY the answer/grammar is what it is (e.g. word order, a grammatical case), shown AFTER the learner answers - regardless of correct or incorrect - unlike ``hint`` (on demand, before/during answering) and ``examples`` (worked examples shown before answering, must not spoil it). Not restricted to any exercise type. Additive; schema_version 1.13.",
"description": "Optional Markdown explanation of WHY the answer/grammar is what it is (e.g. word order, a grammatical case), shown AFTER the learner answers - regardless of correct or incorrect - unlike ``hint`` (on demand, before/during answering) and ``examples`` (worked examples shown before answering, must not spoil it). 2000 chars, twice ``hint``'s 1000: Markdown structure (a short list, bold terms) eats characters faster than a single-line nudge, and a real \"why\" often runs longer than a hint. Not restricted to any exercise type. Additive; schema_version 1.13.",
"title": "Explanation"
},
"ext_payload": {
Expand Down
2 changes: 1 addition & 1 deletion src/types/lesson-schema.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export type Distractors = string[];
*/
export type Examples1 = InlineExample[] | null;
/**
* Optional Markdown explanation of WHY the answer/grammar is what it is (e.g. word order, a grammatical case), shown AFTER the learner answers - regardless of correct or incorrect - unlike ``hint`` (on demand, before/during answering) and ``examples`` (worked examples shown before answering, must not spoil it). Not restricted to any exercise type. Additive; schema_version 1.13.
* Optional Markdown explanation of WHY the answer/grammar is what it is (e.g. word order, a grammatical case), shown AFTER the learner answers - regardless of correct or incorrect - unlike ``hint`` (on demand, before/during answering) and ``examples`` (worked examples shown before answering, must not spoil it). 2000 chars, twice ``hint``'s 1000: Markdown structure (a short list, bold terms) eats characters faster than a single-line nudge, and a real "why" often runs longer than a hint. Not restricted to any exercise type. Additive; schema_version 1.13.
*/
export type Explanation = string | null;
/**
Expand Down
8 changes: 4 additions & 4 deletions src/validate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,12 @@ describe("schema 1.13 — explanation on exercises (idea 5: post-answer 'why')",
expect(validateLesson(lessonWithExplanation(null)).valid).toBe(true);
});

it("boundary: rejects an explanation longer than 1000 characters", () => {
expect(validateLesson(lessonWithExplanation("x".repeat(1001))).valid).toBe(false);
it("boundary: rejects an explanation longer than 2000 characters", () => {
expect(validateLesson(lessonWithExplanation("x".repeat(2001))).valid).toBe(false);
});

it("boundary: accepts an explanation at exactly 1000 characters", () => {
expect(validateLesson(lessonWithExplanation("x".repeat(1000))).valid).toBe(true);
it("boundary: accepts an explanation at exactly 2000 characters", () => {
expect(validateLesson(lessonWithExplanation("x".repeat(2000))).valid).toBe(true);
});

it("is not restricted to one exercise type: a matching exercise may carry it too", () => {
Expand Down
Loading