@intellectif/lk-core 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/{ai-i3jwXnpX.d.cts → ai-B1wYrqcB.d.cts} +39 -15
  3. package/dist/ai-B1wYrqcB.d.cts.map +1 -0
  4. package/dist/{ai-i3jwXnpX.d.ts → ai-B1wYrqcB.d.ts} +39 -15
  5. package/dist/ai-B1wYrqcB.d.ts.map +1 -0
  6. package/dist/ai-check.cjs +13 -6
  7. package/dist/ai-check.cjs.map +1 -1
  8. package/dist/ai-check.d.cts +1 -5
  9. package/dist/ai-check.d.cts.map +1 -1
  10. package/dist/ai-check.d.ts +1 -5
  11. package/dist/ai-check.d.ts.map +1 -1
  12. package/dist/ai-check.js +13 -6
  13. package/dist/ai-check.js.map +1 -1
  14. package/dist/{ai-writing-OJ5m_1EB.js → ai-writing-B7oMCt66.js} +46 -43
  15. package/dist/ai-writing-B7oMCt66.js.map +1 -0
  16. package/dist/{ai-writing-C4YRVrFi.cjs → ai-writing-DrPTV3R2.cjs} +46 -43
  17. package/dist/ai-writing-DrPTV3R2.cjs.map +1 -0
  18. package/dist/{index-DeD8EI1D.d.ts → index-BM8LeDWn.d.cts} +2 -42
  19. package/dist/index-BM8LeDWn.d.cts.map +1 -0
  20. package/dist/{index-Uh1u57yq.d.cts → index-BTkMQtws.d.ts} +2 -42
  21. package/dist/index-BTkMQtws.d.ts.map +1 -0
  22. package/dist/{index-Dj92T76o.d.ts → index-BU99GFTl.d.ts} +2 -8
  23. package/dist/index-BU99GFTl.d.ts.map +1 -0
  24. package/dist/{index-WBHSrIUU.d.ts → index-BdXs4-en.d.ts} +5 -12
  25. package/dist/index-BdXs4-en.d.ts.map +1 -0
  26. package/dist/{index-CFRgZLhH.d.cts → index-DP9rvyOz.d.cts} +5 -12
  27. package/dist/index-DP9rvyOz.d.cts.map +1 -0
  28. package/dist/{index--U7hHV0s.d.cts → index-XCCoPoTU.d.cts} +2 -8
  29. package/dist/index-XCCoPoTU.d.cts.map +1 -0
  30. package/dist/index.cjs +13 -20
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +4 -70
  33. package/dist/index.d.cts.map +1 -1
  34. package/dist/index.d.ts +4 -70
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +13 -20
  37. package/dist/index.js.map +1 -1
  38. package/dist/{item-group-CQRbb8Rx.cjs → item-group-8P3WFuUK.cjs} +4 -6
  39. package/dist/{item-group-CQRbb8Rx.cjs.map → item-group-8P3WFuUK.cjs.map} +1 -1
  40. package/dist/{item-group-BbvvH_Ob.js → item-group-CeDk7mfM.js} +4 -6
  41. package/dist/{item-group-BbvvH_Ob.js.map → item-group-CeDk7mfM.js.map} +1 -1
  42. package/dist/{registry-B23o9UWh.js → registry-D92hz9iA.js} +60 -89
  43. package/dist/registry-D92hz9iA.js.map +1 -0
  44. package/dist/{registry-Ih5n4PVZ.cjs → registry-hzrkTeIT.cjs} +61 -91
  45. package/dist/registry-hzrkTeIT.cjs.map +1 -0
  46. package/dist/{schemas-Q2dyOgc2.cjs → schemas-BWeskONy.cjs} +5 -7
  47. package/dist/{schemas-Q2dyOgc2.cjs.map → schemas-BWeskONy.cjs.map} +1 -1
  48. package/dist/{schemas-yId-bJhD.js → schemas-C7TViWCg.js} +5 -7
  49. package/dist/{schemas-yId-bJhD.js.map → schemas-C7TViWCg.js.map} +1 -1
  50. package/dist/schemas.cjs +3 -3
  51. package/dist/schemas.d.cts +1 -1
  52. package/dist/schemas.d.ts +1 -1
  53. package/dist/schemas.js +3 -3
  54. package/dist/{scoring-CaPS6q8b.cjs → scoring-CtkCFyFT.cjs} +22 -42
  55. package/dist/{scoring-CaPS6q8b.cjs.map → scoring-CtkCFyFT.cjs.map} +1 -1
  56. package/dist/{scoring-CLMdk8i9.js → scoring-DD1GHcLI.js} +22 -42
  57. package/dist/{scoring-CLMdk8i9.js.map → scoring-DD1GHcLI.js.map} +1 -1
  58. package/dist/scoring.cjs +2 -2
  59. package/dist/scoring.d.cts +2 -2
  60. package/dist/scoring.d.ts +2 -2
  61. package/dist/scoring.js +2 -2
  62. package/dist/{xapi-BX0hvRRB.cjs → xapi-7btSpx6v.cjs} +5 -8
  63. package/dist/{xapi-BX0hvRRB.cjs.map → xapi-7btSpx6v.cjs.map} +1 -1
  64. package/dist/{xapi-Cdk9fTvV.js → xapi-Cgicg-zU.js} +5 -8
  65. package/dist/{xapi-Cdk9fTvV.js.map → xapi-Cgicg-zU.js.map} +1 -1
  66. package/dist/xapi.cjs +1 -1
  67. package/dist/xapi.d.cts +1 -1
  68. package/dist/xapi.d.ts +1 -1
  69. package/dist/xapi.js +1 -1
  70. package/package.json +2 -2
  71. package/dist/ai-i3jwXnpX.d.cts.map +0 -1
  72. package/dist/ai-i3jwXnpX.d.ts.map +0 -1
  73. package/dist/ai-writing-C4YRVrFi.cjs.map +0 -1
  74. package/dist/ai-writing-OJ5m_1EB.js.map +0 -1
  75. package/dist/index--U7hHV0s.d.cts.map +0 -1
  76. package/dist/index-CFRgZLhH.d.cts.map +0 -1
  77. package/dist/index-DeD8EI1D.d.ts.map +0 -1
  78. package/dist/index-Dj92T76o.d.ts.map +0 -1
  79. package/dist/index-Uh1u57yq.d.cts.map +0 -1
  80. package/dist/index-WBHSrIUU.d.ts.map +0 -1
  81. package/dist/registry-B23o9UWh.js.map +0 -1
  82. package/dist/registry-Ih5n4PVZ.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import * as z from "zod/v4";
2
2
  import { $ZodCheck } from "zod/v4/core";
3
- //#region src/schemas/ai.ts
3
+ // src/schemas/ai.ts
4
4
  /**
5
5
  * What an author allows AI to do for one item: see `ActivityAiPermissions`.
6
6
  * Loose like every content schema, so a key a later release adds survives an
@@ -10,8 +10,7 @@ const AiPermissionsSchema = z.looseObject({
10
10
  explanations: z.boolean().optional(),
11
11
  hints: z.boolean().optional()
12
12
  });
13
- //#endregion
14
- //#region src/schemas/feedback.ts
13
+ // src/schemas/feedback.ts
15
14
  /**
16
15
  * Optional authored "overall feedback" shown after submission, selected by
17
16
  * whether the learner passed (h5p-style overall feedback). Both fields are
@@ -21,8 +20,7 @@ const FeedbackSchema = z.looseObject({
21
20
  correct: z.string().min(1).optional(),
22
21
  incorrect: z.string().min(1).optional()
23
22
  });
24
- //#endregion
25
- //#region src/schemas/text-length.ts
23
+ // src/schemas/text-length.ts
26
24
  /**
27
25
  * `schema`, refusing a string longer than `max` UTF-16 code units — its
28
26
  * JavaScript `length`, the unit these limits have always counted in.
@@ -45,8 +43,7 @@ function maxUnits(schema, max) {
45
43
  });
46
44
  }).meta({ maxLength: max });
47
45
  }
48
- //#endregion
49
- //#region src/schemas/media.ts
46
+ // src/schemas/media.ts
50
47
  /**
51
48
  * Optional media attached to an activity, rendered above the question or
52
49
  * passage — e.g. a recording to listen to, or an embedded video to watch
@@ -244,8 +241,7 @@ const RedactedMediaSchema = z.strictObject({
244
241
  error: "embed media requires an absolute http(s) provider URL. data:, blob:, and relative URLs are not allowed for embeds — the embed iframe runs with allow-scripts, and a data:/same-origin document there is an XSS vector.",
245
242
  path: ["url"]
246
243
  }).refine(posterFits, POSTER_FITS).refine(tracksFit, TRACKS_FIT).refine(tracksAreDistinct, TRACKS_DISTINCT);
247
- //#endregion
248
- //#region src/schemas/fill-in-the-blanks.ts
244
+ // src/schemas/fill-in-the-blanks.ts
249
245
  /**
250
246
  * Matches `{{ blank_id }}` placeholders in a passage, capturing the trimmed id.
251
247
  * Exported for the draft checks in `authoring/`, which must read a passage
@@ -253,6 +249,12 @@ const RedactedMediaSchema = z.strictObject({
253
249
  */
254
250
  const PLACEHOLDER_RE = /\{\{\s*([^{}]+?)\s*\}\}/g;
255
251
  /**
252
+ * The instructions of an item with a passage: plain text, with no `{{id}}`
253
+ * placeholder. Blanks and gaps live in the passage only, and one written here
254
+ * would be shown to the learner as it stands. Shared by Gap Select.
255
+ */
256
+ const PassageInstructionsSchema = z.string().refine((text) => text.match(PLACEHOLDER_RE) === null, { error: "The instructions are plain text: a {{id}} placeholder belongs in the passage, where its blank or gap is." });
257
+ /**
256
258
  * Zod schema for a `TextMatchPolicy` — the opt-in matching tolerances a blank
257
259
  * may declare. Every default reproduces the v1 trim + case-fold semantics.
258
260
  */
@@ -300,6 +302,7 @@ const FillInTheBlanksDataSchema = z.looseObject({
300
302
  type: z.literal("fill-in-the-blanks"),
301
303
  id: z.string().min(1),
302
304
  title: z.string().min(1),
305
+ instructions: PassageInstructionsSchema.optional(),
303
306
  passage: z.string().min(1),
304
307
  passageHtml: z.string().optional(),
305
308
  blanks: z.array(BlankConfigSchema).min(1),
@@ -331,8 +334,7 @@ const FillInTheBlanksDataSchema = z.looseObject({
331
334
  error: "Each blank id must appear exactly once in blanks[] and have exactly one matching {{id}} placeholder in the passage, and vice versa.",
332
335
  path: ["passage"]
333
336
  });
334
- //#endregion
335
- //#region src/answer-leak.ts
337
+ // src/answer-leak.ts
336
338
  /**
337
339
  * Whether a text gives an answer away: the rule an AI hint is held to, and the
338
340
  * one the item critic holds an author's own hint, title and passage to.
@@ -419,8 +421,7 @@ function revealsAnswer(text, answer, passage, position) {
419
421
  if (before === void 0 && after === void 0) return containsWords(words, needle);
420
422
  return before !== void 0 && containsWords(words, [before, ...needle]) || after !== void 0 && containsWords(words, [...needle, after]);
421
423
  }
422
- //#endregion
423
- //#region src/built-in-types.ts
424
+ // src/built-in-types.ts
424
425
  /**
425
426
  * The activity types the SDK ships, in one closed list.
426
427
  *
@@ -456,8 +457,7 @@ function isBuiltInActivityType(type) {
456
457
  * @internal
457
458
  */
458
459
  function everyBuiltInTypeHandled(_value) {}
459
- //#endregion
460
- //#region src/scoring/dictation/edit-distance.ts
460
+ // src/scoring/dictation/edit-distance.ts
461
461
  /**
462
462
  * The code points of `text`, as numbers. A surrogate pair is one code point; a
463
463
  * lone surrogate iterates as one code point too — deterministic, never thrown.
@@ -509,8 +509,7 @@ function similarity(a, b) {
509
509
  const max = Math.max(codePoints(a).length, codePoints(b).length);
510
510
  return max === 0 ? 0 : (max - editDistance(a, b)) / max;
511
511
  }
512
- //#endregion
513
- //#region src/validation-scope.ts
512
+ // src/validation-scope.ts
514
513
  /**
515
514
  * Work shared for the length of one outermost validation call.
516
515
  *
@@ -549,8 +548,7 @@ function scopeCache(key, create) {
549
548
  }
550
549
  return value;
551
550
  }
552
- //#endregion
553
- //#region src/scoring/dictation/unicode-joining.ts
551
+ // src/scoring/dictation/unicode-joining.ts
554
552
  /**
555
553
  * Unicode data the dictation normaliser reads when it decides whether a joiner
556
554
  * changes how the text is drawn (see `normalize.ts`): the viramas, and which
@@ -768,8 +766,7 @@ const JOINS_BACKWARD = [
768
766
  [69577, 69578],
769
767
  [125184, 125251]
770
768
  ];
771
- //#endregion
772
- //#region src/scoring/dictation/normalize.ts
769
+ // src/scoring/dictation/normalize.ts
773
770
  /**
774
771
  * The longest transcript a dictation accepts, in code points, before and after
775
772
  * its equivalences are applied — and its rules may not grow it past twice
@@ -1729,8 +1726,7 @@ function searchReveal(forms, candidate) {
1729
1726
  return fields.some((field) => containsPhrase(field, phrase));
1730
1727
  });
1731
1728
  }
1732
- //#endregion
1733
- //#region src/scoring/dictation/align.ts
1729
+ // src/scoring/dictation/align.ts
1734
1730
  /**
1735
1731
  * The words the scorer can emit a detail for, one list per candidate — index 0
1736
1732
  * is the transcript, index n is `acceptedTranscripts[n − 1]` — each word in the
@@ -1929,8 +1925,7 @@ function alignWords(reference, attempt) {
1929
1925
  }
1930
1926
  return words;
1931
1927
  }
1932
- //#endregion
1933
- //#region src/errors.ts
1928
+ // src/errors.ts
1934
1929
  /** Thrown when activity data fails schema validation at a component boundary. */
1935
1930
  var ActivitySchemaError = class extends Error {
1936
1931
  activityType;
@@ -1984,8 +1979,7 @@ var DeferredScoringError = class extends Error {
1984
1979
  this.name = "DeferredScoringError";
1985
1980
  }
1986
1981
  };
1987
- //#endregion
1988
- //#region src/schemas/after-issues.ts
1982
+ // src/schemas/after-issues.ts
1989
1983
  /**
1990
1984
  * A check zod runs even when another field was refused. An ordinary check is
1991
1985
  * skipped once any issue has been reported, so an author fixing a recording's
@@ -2022,8 +2016,7 @@ function parsedFields(payload) {
2022
2016
  refused
2023
2017
  };
2024
2018
  }
2025
- //#endregion
2026
- //#region src/schemas/dictation.ts
2019
+ // src/schemas/dictation.ts
2027
2020
  /**
2028
2021
  * Zod schema for the slower second recording of a dictation. Loose like every
2029
2022
  * content schema (a sidecar survives), audio only, and — deliberately — with no
@@ -2205,8 +2198,7 @@ function groupCaptionsField(group, written) {
2205
2198
  }
2206
2199
  /** The message every validator gives for {@link groupCaptionsRevealDictation}. */
2207
2200
  const GROUP_CAPTIONS_REVEAL_DICTATION = "The stimulus recording carries captions, and a dictation in this group plays that recording: the captions are the answer. Remove the captions, or give the dictation its own recording.";
2208
- //#endregion
2209
- //#region src/authoring/issues.ts
2201
+ // src/authoring/issues.ts
2210
2202
  /**
2211
2203
  * Every issue code the SDK's draft checks can report, with its severity.
2212
2204
  *
@@ -2542,8 +2534,7 @@ function coveredPathsOf(reported) {
2542
2534
  }
2543
2535
  return covered;
2544
2536
  }
2545
- //#endregion
2546
- //#region src/authoring/dictation.ts
2537
+ // src/authoring/dictation.ts
2547
2538
  /**
2548
2539
  * Draft support for `dictation`.
2549
2540
  *
@@ -2733,8 +2724,7 @@ function checkTolerance(tolerance) {
2733
2724
  }
2734
2725
  return issues;
2735
2726
  }
2736
- //#endregion
2737
- //#region src/count-words.ts
2727
+ // src/count-words.ts
2738
2728
  /**
2739
2729
  * Canonical word counter for written-response bounds: tokens are
2740
2730
  * maximal runs of non-whitespace (split on `\s+`), so hyphenated forms
@@ -2839,8 +2829,7 @@ function levelDistribution(values, count, chosen) {
2839
2829
  const sum = read.reduce((total, p) => total + p, 0);
2840
2830
  return Math.abs(sum - 1) <= 1e-6 && read[chosen] === Math.max(...read) ? read : null;
2841
2831
  }
2842
- //#endregion
2843
- //#region src/scoring/strategies/all-or-nothing.ts
2832
+ // src/scoring/strategies/all-or-nothing.ts
2844
2833
  /**
2845
2834
  * All-or-nothing scoring: full credit only when every item is correct.
2846
2835
  *
@@ -2850,8 +2839,7 @@ function levelDistribution(values, count, chosen) {
2850
2839
  function allOrNothingStrategy(correctItems) {
2851
2840
  return correctItems.every((isCorrect) => isCorrect) ? 1 : 0;
2852
2841
  }
2853
- //#endregion
2854
- //#region src/scoring/strategies/partial.ts
2842
+ // src/scoring/strategies/partial.ts
2855
2843
  /**
2856
2844
  * Partial-credit scoring for Multiple Choice — balanced/symmetric scheme.
2857
2845
  *
@@ -2891,8 +2879,7 @@ function partialStrategy(correctSelected, incorrectSelected, totalCorrect, total
2891
2879
  function partialBlankStrategy(correctBlanks, totalBlanks) {
2892
2880
  return correctBlanks / totalBlanks;
2893
2881
  }
2894
- //#endregion
2895
- //#region src/scoring/text-match.ts
2882
+ // src/scoring/text-match.ts
2896
2883
  /** Combining marks (any script) removed for diacritic folding after NFD decomposition. */
2897
2884
  const COMBINING_MARKS_RE = /\p{M}/gu;
2898
2885
  /**
@@ -2985,8 +2972,7 @@ function matchText(input, accepted, policy = {}) {
2985
2972
  via: "none"
2986
2973
  };
2987
2974
  }
2988
- //#endregion
2989
- //#region src/scoring/activity-scorers/fill-in-the-blanks.ts
2975
+ // src/scoring/activity-scorers/fill-in-the-blanks.ts
2990
2976
  /**
2991
2977
  * Resolves the effective match policy for a blank. The legacy
2992
2978
  * `caseSensitive` / `trimWhitespace` flags map onto the baseline policy
@@ -3030,8 +3016,7 @@ function scoreFillInTheBlanks(data, response) {
3030
3016
  details
3031
3017
  };
3032
3018
  }
3033
- //#endregion
3034
- //#region src/authoring/findings.ts
3019
+ // src/authoring/findings.ts
3035
3020
  /**
3036
3021
  * Every finding code the SDK's item critic can report, with its severity.
3037
3022
  *
@@ -3084,8 +3069,7 @@ function normaliseFinding(found) {
3084
3069
  severity: documented ?? (found.severity === "advice" ? "advice" : "warning")
3085
3070
  };
3086
3071
  }
3087
- //#endregion
3088
- //#region src/authoring/critique.ts
3072
+ // src/authoring/critique.ts
3089
3073
  /**
3090
3074
  * The built-in item critic: what an experienced item writer points out on
3091
3075
  * review, as far as a rule can see it without a model.
@@ -3368,8 +3352,7 @@ function keyPositionFinding(items, path) {
3368
3352
  if (positions.length < KEY_POSITION_MINIMUM || !positions.every((at) => at === positions[0])) return [];
3369
3353
  return [finding("set_key_position_same", path, `In all ${positions.length} single-answer questions the right option is option ${ordinal(positions[0])}. Vary its position, or shuffle the options.`)];
3370
3354
  }
3371
- //#endregion
3372
- //#region src/authoring/fill-in-the-blanks.ts
3355
+ // src/authoring/fill-in-the-blanks.ts
3373
3356
  /**
3374
3357
  * Draft support for `fill-in-the-blanks`.
3375
3358
  *
@@ -3501,8 +3484,7 @@ function pairsOneToOne$1(placeholders, blanks) {
3501
3484
  if (placeholders.size !== blankIds.length) return false;
3502
3485
  return blankIds.every((id) => typeof id === "string" && placeholders.get(id) === 1);
3503
3486
  }
3504
- //#endregion
3505
- //#region src/authoring/gap-select.ts
3487
+ // src/authoring/gap-select.ts
3506
3488
  /** Mirrors `GapSelectChoiceSchema` arrays: `.min(2)` on both a gap's own list and a bank. */
3507
3489
  const MIN_CHOICES = 2;
3508
3490
  /**
@@ -3700,8 +3682,7 @@ function pairsOneToOne(placeholders, gaps) {
3700
3682
  if (new Set(ids).size !== ids.length || placeholders.size !== ids.length) return false;
3701
3683
  return ids.every((id) => typeof id === "string" && placeholders.get(id) === 1);
3702
3684
  }
3703
- //#endregion
3704
- //#region src/schemas/multiple-choice.ts
3685
+ // src/schemas/multiple-choice.ts
3705
3686
  /**
3706
3687
  * Zod schema for a single Multiple Choice option. Loose: unknown keys are
3707
3688
  * preserved through validation (forward-compat / consumer sidecars — B7).
@@ -3765,6 +3746,7 @@ const MultipleChoiceDataSchema = z.looseObject({
3765
3746
  type: z.literal("multiple-choice"),
3766
3747
  id: z.string().min(1),
3767
3748
  title: z.string().min(1),
3749
+ instructions: z.string().optional(),
3768
3750
  question: z.string().min(1),
3769
3751
  questionHtml: z.string().optional(),
3770
3752
  mode: z.enum(["single", "multi"]),
@@ -3794,8 +3776,7 @@ const MultipleChoiceDataSchema = z.looseObject({
3794
3776
  error: "Option ids must be unique within the activity.",
3795
3777
  path: ["options"]
3796
3778
  });
3797
- //#endregion
3798
- //#region src/authoring/multiple-choice.ts
3779
+ // src/authoring/multiple-choice.ts
3799
3780
  /** Mirrors `MultipleChoiceDataSchema`: `options` is `.min(2).max(26)`. */
3800
3781
  const MIN_OPTIONS = 2;
3801
3782
  const MAX_OPTIONS = 26;
@@ -3898,8 +3879,7 @@ function checkOptionMedia(media, index, ordinal) {
3898
3879
  if (kind === "video" || kind === "embed") return [issue("mc_option_media_kind", [...path, "type"], `Option ${ordinal} carries ${kind === "embed" ? "an embedded player" : "a video"}, which cannot be an option: its controls swallow the click that selects the answer. Use a picture or a recording.`)];
3899
3880
  return checkMedia(media, path, MultipleChoiceOptionMediaSchema);
3900
3881
  }
3901
- //#endregion
3902
- //#region src/scoring/speech/limits.ts
3882
+ // src/scoring/speech/limits.ts
3903
3883
  /**
3904
3884
  * The longest reference text a read-aloud item accepts, in code points, before
3905
3885
  * and after normalisation. It is the dictation transcript cap on purpose: the
@@ -3949,8 +3929,7 @@ const SPEECH_ASSESSMENT_MAX_WORDS = 1e3;
3949
3929
  * read-aloud item comes near it.
3950
3930
  */
3951
3931
  const SPEECH_ASSESSMENT_MAX_TEXT_LENGTH = DICTATION_MAX_TEXT_LENGTH;
3952
- //#endregion
3953
- //#region src/scoring/speech/locale.ts
3932
+ // src/scoring/speech/locale.ts
3954
3933
  /**
3955
3934
  * A BCP 47 tag in the one spelling read-aloud accepts: a lowercase language of
3956
3935
  * two or three letters, an optional title-case script, and a region of two
@@ -3966,8 +3945,7 @@ const SPEECH_ASSESSMENT_MAX_TEXT_LENGTH = DICTATION_MAX_TEXT_LENGTH;
3966
3945
  * Internal: the content schema and the assessment validator share it.
3967
3946
  */
3968
3947
  const CANONICAL_LOCALE_RE = /^[a-z]{2,3}(?:-[A-Z][a-z]{3})?-(?:[A-Z]{2}|[0-9]{3})$/;
3969
- //#endregion
3970
- //#region src/schemas/read-aloud.ts
3948
+ // src/schemas/read-aloud.ts
3971
3949
  /** The dimensions a read-aloud grade can be made of, in the order they are documented. */
3972
3950
  const READ_ALOUD_DIMENSIONS = [
3973
3951
  "accuracy",
@@ -4120,8 +4098,7 @@ const ReadAloudDataSchema = z.looseObject({
4120
4098
  if (minSeconds !== void 0 && minSeconds >= maxSeconds) report(["recording", "minSeconds"], minSeconds, "The shortest take must be shorter than the longest.");
4121
4099
  }
4122
4100
  }));
4123
- //#endregion
4124
- //#region src/authoring/read-aloud.ts
4101
+ // src/authoring/read-aloud.ts
4125
4102
  /**
4126
4103
  * Draft support for `read-aloud`.
4127
4104
  *
@@ -4284,8 +4261,7 @@ function checkSlowRecording(draft) {
4284
4261
  if (typeof slow.url === "string" && slow.url !== "" && slow.url === media.url) issues.push(issue("ra_slow_media_same_recording", ["slowMedia", "url"], "The slow model recording is the same file as the recording. Point it at the slower reading."));
4285
4262
  return issues;
4286
4263
  }
4287
- //#endregion
4288
- //#region src/authoring/written-response.ts
4264
+ // src/authoring/written-response.ts
4289
4265
  /**
4290
4266
  * Draft support for `written-response`.
4291
4267
  *
@@ -4373,8 +4349,7 @@ function checkCriteria(criteria) {
4373
4349
  else if (totalWeight === Number.POSITIVE_INFINITY) issues.push(issue("wr_rubric_weights_too_large", ["rubric", "criteria"], "The rubric weights add up to more than can be calculated with. Use smaller weights."));
4374
4350
  return issues;
4375
4351
  }
4376
- //#endregion
4377
- //#region src/schemas/gap-select.ts
4352
+ // src/schemas/gap-select.ts
4378
4353
  /**
4379
4354
  * Zod schema for one selectable choice. Loose, like every other schema here:
4380
4355
  * unknown keys are preserved so a consumer sidecar survives validation.
@@ -4438,6 +4413,7 @@ const GapSelectDataSchema = z.looseObject({
4438
4413
  type: z.literal("gap-select"),
4439
4414
  id: z.string().min(1),
4440
4415
  title: z.string().min(1),
4416
+ instructions: PassageInstructionsSchema.optional(),
4441
4417
  passage: z.string().min(1),
4442
4418
  passageHtml: z.string().optional(),
4443
4419
  gaps: z.array(GapSelectGapSchema).min(1),
@@ -4498,8 +4474,7 @@ const GapSelectDataSchema = z.looseObject({
4498
4474
  error: "Each gap needs unique choice ids and a `correctChoiceId` that is one of the choices it offers.",
4499
4475
  path: ["gaps"]
4500
4476
  });
4501
- //#endregion
4502
- //#region src/schemas/written-response.ts
4477
+ // src/schemas/written-response.ts
4503
4478
  /** Zod schema for a single rubric criterion. Loose: unknown keys preserved. */
4504
4479
  const WrittenResponseRubricCriterionSchema = z.looseObject({
4505
4480
  name: z.string().min(1),
@@ -4570,8 +4545,7 @@ const WrittenResponseDataSchema = z.looseObject({
4570
4545
  error: "maxWords must be greater than or equal to minWords.",
4571
4546
  path: ["maxWords"]
4572
4547
  });
4573
- //#endregion
4574
- //#region src/schemas/redacted.ts
4548
+ // src/schemas/redacted.ts
4575
4549
  /**
4576
4550
  * Schemas for REDACTED activity data — the learner-safe projection `redact()`
4577
4551
  * produces (R7). Deliberately STRICT (`z.strictObject`), the opposite of the
@@ -4635,6 +4609,7 @@ const RedactedMultipleChoiceOptionSchema = z.strictObject({
4635
4609
  const RedactedMultipleChoiceDataSchema = z.strictObject({
4636
4610
  ...redactedBase,
4637
4611
  type: z.literal("multiple-choice"),
4612
+ instructions: z.string().optional(),
4638
4613
  question: z.string().min(1),
4639
4614
  questionHtml: z.string().optional(),
4640
4615
  mode: z.enum(["single", "multi"]),
@@ -4650,6 +4625,7 @@ const RedactedBlankConfigSchema = z.strictObject({
4650
4625
  const RedactedFillInTheBlanksDataSchema = z.strictObject({
4651
4626
  ...redactedBase,
4652
4627
  type: z.literal("fill-in-the-blanks"),
4628
+ instructions: z.string().optional(),
4653
4629
  passage: z.string().min(1),
4654
4630
  passageHtml: z.string().optional(),
4655
4631
  blanks: z.array(RedactedBlankConfigSchema).min(1)
@@ -4688,6 +4664,7 @@ const RedactedGapSelectGapSchema = z.strictObject({
4688
4664
  const RedactedGapSelectDataSchema = z.strictObject({
4689
4665
  ...redactedBase,
4690
4666
  type: z.literal("gap-select"),
4667
+ instructions: z.string().optional(),
4691
4668
  passage: z.string().min(1),
4692
4669
  passageHtml: z.string().optional(),
4693
4670
  gaps: z.array(RedactedGapSelectGapSchema).min(1),
@@ -4813,8 +4790,7 @@ const RedactedReadAloudDataSchema = z.strictObject({
4813
4790
  path: ["slowMedia", "url"]
4814
4791
  });
4815
4792
  });
4816
- //#endregion
4817
- //#region src/scoring/activity-scorers/dictation.ts
4793
+ // src/scoring/activity-scorers/dictation.ts
4818
4794
  /**
4819
4795
  * Scores a Dictation response: the character-level similarity of what the
4820
4796
  * learner typed to the transcript, over the whole sentence.
@@ -4853,8 +4829,7 @@ function scoreDictation(data, response) {
4853
4829
  details
4854
4830
  };
4855
4831
  }
4856
- //#endregion
4857
- //#region src/scoring/activity-scorers/gap-select.ts
4832
+ // src/scoring/activity-scorers/gap-select.ts
4858
4833
  /**
4859
4834
  * The choices a gap offers: its own list, or the bank it names.
4860
4835
  *
@@ -4908,8 +4883,7 @@ function scoreGapSelect(data, response) {
4908
4883
  details
4909
4884
  };
4910
4885
  }
4911
- //#endregion
4912
- //#region src/scoring/activity-scorers/multiple-choice.ts
4886
+ // src/scoring/activity-scorers/multiple-choice.ts
4913
4887
  /**
4914
4888
  * Scores a Multiple Choice response. Pure; trusts its typed inputs (validation
4915
4889
  * is the component boundary's job). Options are looked up by id; an unknown
@@ -4953,8 +4927,7 @@ function scoreMultipleChoice(data, response) {
4953
4927
  details
4954
4928
  };
4955
4929
  }
4956
- //#endregion
4957
- //#region src/registry/define.ts
4930
+ // src/registry/define.ts
4958
4931
  /**
4959
4932
  * Identity helper that gives full type inference when authoring a descriptor:
4960
4933
  *
@@ -4969,8 +4942,7 @@ function scoreMultipleChoice(data, response) {
4969
4942
  function defineActivityType(descriptor) {
4970
4943
  return descriptor;
4971
4944
  }
4972
- //#endregion
4973
- //#region src/registry/keep-when.ts
4945
+ // src/registry/keep-when.ts
4974
4946
  /**
4975
4947
  * A nested field policy that keeps its field only when the field's value
4976
4948
  * passes a test. Internal: the symbol is never exported, so no host policy can
@@ -4995,8 +4967,7 @@ function keepWhen(policy, test) {
4995
4967
  function guardOf(policy) {
4996
4968
  return policy[KEEP_WHEN];
4997
4969
  }
4998
- //#endregion
4999
- //#region src/registry/builtins.ts
4970
+ // src/registry/builtins.ts
5000
4971
  /**
5001
4972
  * Where the built-in types keep their files (`mediaSlots`). Every type has its
5002
4973
  * `media`; dictation and read-aloud add a slower recording; a multiple-choice
@@ -5114,6 +5085,7 @@ const TEXT_MATCH_FIELD_POLICY = {
5114
5085
  };
5115
5086
  const MULTIPLE_CHOICE_FIELD_POLICY = {
5116
5087
  ...SHARED_PUBLIC_FIELDS,
5088
+ instructions: "public",
5117
5089
  question: "public",
5118
5090
  questionHtml: "public",
5119
5091
  mode: "public",
@@ -5148,6 +5120,7 @@ const MULTIPLE_CHOICE_FIELD_POLICY = {
5148
5120
  */
5149
5121
  const GAP_SELECT_FIELD_POLICY = {
5150
5122
  ...SHARED_PUBLIC_FIELDS,
5123
+ instructions: "public",
5151
5124
  passage: "public",
5152
5125
  passageHtml: "public",
5153
5126
  presentation: "public",
@@ -5174,6 +5147,7 @@ const GAP_SELECT_FIELD_POLICY = {
5174
5147
  };
5175
5148
  const FILL_IN_THE_BLANKS_FIELD_POLICY = {
5176
5149
  ...SHARED_PUBLIC_FIELDS,
5150
+ instructions: "public",
5177
5151
  passage: "public",
5178
5152
  passageHtml: "public",
5179
5153
  scoringStrategy: "answer-key",
@@ -5476,8 +5450,7 @@ const BUILT_IN_DESCRIPTORS = {
5476
5450
  dictation: dictationType,
5477
5451
  "read-aloud": readAloudType
5478
5452
  };
5479
- //#endregion
5480
- //#region src/schemas/read-schema.ts
5453
+ // src/schemas/read-schema.ts
5481
5454
  /**
5482
5455
  * How every entry point reads a schema — `validateActivity`, `validateDraft`,
5483
5456
  * `validateItemGroup`, `redact`, `assertRedacted` — so a schema is read one way
@@ -5593,8 +5566,7 @@ function standardJsonSchemaOf(schema, target = "draft-07") {
5593
5566
  const generated = converter.output({ target });
5594
5567
  return generated !== null && typeof generated === "object" && !Array.isArray(generated) ? generated : void 0;
5595
5568
  }
5596
- //#endregion
5597
- //#region src/registry/registry.ts
5569
+ // src/registry/registry.ts
5598
5570
  /**
5599
5571
  * Module-scoped default registry (deliberate — no registry instances until a
5600
5572
  * second consumer exists), created holding the SDK's own types.
@@ -5640,7 +5612,6 @@ function getActivityTypeDescriptor(type) {
5640
5612
  function registeredActivityTypes() {
5641
5613
  return [...registry.keys()];
5642
5614
  }
5643
- //#endregion
5644
5615
  export { DeferredScoringError as $, normaliseFinding as A, coveredPathsOf as B, READ_ALOUD_MAX_TAKES as C, MediaSchema as Ct, MultipleChoiceOptionMediaSchema as D, maxUnits as Dt, MultipleChoiceDataSchema as E, ScriptSchema as Et, levelKey as F, isUnwritten as G, isMissingId as H, readRubricLevels as I, refusesEmpty as J, issue as K, countWords as L, matchText as M, LEVEL_PROBABILITY_TOLERANCE as N, keyPositionFinding as O, levelDistribution as P, ActivitySchemaError as Q, DRAFT_ISSUE_SEVERITY as R, READ_ALOUD_MAX_SECONDS as S, FillInTheBlanksDataSchema as St, SPEECH_ASSESSMENT_MAX_WORDS as T, SCRIPT_MAX_TURNS as Tt, isRecord as U, covers as V, isUnset as W, GROUP_CAPTIONS_REVEAL_DICTATION as X, DictationDataSchema as Y, groupCaptionsField as Z, GapSelectDataSchema as _, containsWords as _t, readSchema as a, dictationReferenceWords as at, READ_ALOUD_MAX_DIMENSION_WEIGHT as b, placeholderOrder as bt, dictationType as c, DICTATION_MAX_EQUIVALENCE_LENGTH as ct, multipleChoiceType as d, codePointLength as dt, RedactedScoringError as et, readAloudType as f, normalizeDictationText as ft, WrittenResponseDataSchema as g, isBuiltInActivityType as gt, defineActivityType as h, everyBuiltInTypeHandled as ht, isOwnSchema as i, alignSequences as it, levenshteinDistance as j, finding as k, fillInTheBlanksType as l, DICTATION_MAX_TEXT_LENGTH as lt, guardOf as m, BUILT_IN_ACTIVITY_TYPES as mt, registerActivityType as n, STEP as nt, standardJsonSchemaOf as o, DICTATION_MAX_ACCEPTED_TRANSCRIPTS as ot, writtenResponseType as p, withValidationScope as pt, pathKey as q, registeredActivityTypes as r, alignDictation as rt, MEDIA_FIELD_POLICY as s, DICTATION_MAX_EQUIVALENCES as st, getActivityTypeDescriptor as t, UnknownActivityTypeError as tt, gapSelectType as u, DICTATION_MAX_TRANSCRIPT_LENGTH as ut, ReadAloudDataSchema as v, fold as vt, SPEECH_ASSESSMENT_MAX_TEXT_LENGTH as w, RedactedMediaSchema as wt, READ_ALOUD_MAX_REFERENCE_LENGTH as x, revealsAnswer as xt, CANONICAL_LOCALE_RE as y, numberedPassage as yt, checkMedia as z };
5645
5616
 
5646
- //# sourceMappingURL=registry-B23o9UWh.js.map
5617
+ //# sourceMappingURL=registry-D92hz9iA.js.map