@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,4 +1,4 @@
1
- //#region \0rolldown/runtime.js
1
+ // \0rolldown/runtime.js
2
2
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -19,11 +19,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
19
19
  value: mod,
20
20
  enumerable: true
21
21
  }) : target, mod));
22
- //#endregion
23
22
  let zod_v4 = require("zod/v4");
24
23
  zod_v4 = __toESM(zod_v4, 1);
25
24
  let zod_v4_core = require("zod/v4/core");
26
- //#region src/schemas/ai.ts
25
+ // src/schemas/ai.ts
27
26
  /**
28
27
  * What an author allows AI to do for one item: see `ActivityAiPermissions`.
29
28
  * Loose like every content schema, so a key a later release adds survives an
@@ -33,8 +32,7 @@ const AiPermissionsSchema = zod_v4.looseObject({
33
32
  explanations: zod_v4.boolean().optional(),
34
33
  hints: zod_v4.boolean().optional()
35
34
  });
36
- //#endregion
37
- //#region src/schemas/feedback.ts
35
+ // src/schemas/feedback.ts
38
36
  /**
39
37
  * Optional authored "overall feedback" shown after submission, selected by
40
38
  * whether the learner passed (h5p-style overall feedback). Both fields are
@@ -44,8 +42,7 @@ const FeedbackSchema = zod_v4.looseObject({
44
42
  correct: zod_v4.string().min(1).optional(),
45
43
  incorrect: zod_v4.string().min(1).optional()
46
44
  });
47
- //#endregion
48
- //#region src/schemas/text-length.ts
45
+ // src/schemas/text-length.ts
49
46
  /**
50
47
  * `schema`, refusing a string longer than `max` UTF-16 code units — its
51
48
  * JavaScript `length`, the unit these limits have always counted in.
@@ -68,8 +65,7 @@ function maxUnits(schema, max) {
68
65
  });
69
66
  }).meta({ maxLength: max });
70
67
  }
71
- //#endregion
72
- //#region src/schemas/media.ts
68
+ // src/schemas/media.ts
73
69
  /**
74
70
  * Optional media attached to an activity, rendered above the question or
75
71
  * passage — e.g. a recording to listen to, or an embedded video to watch
@@ -267,8 +263,7 @@ const RedactedMediaSchema = zod_v4.strictObject({
267
263
  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.",
268
264
  path: ["url"]
269
265
  }).refine(posterFits, POSTER_FITS).refine(tracksFit, TRACKS_FIT).refine(tracksAreDistinct, TRACKS_DISTINCT);
270
- //#endregion
271
- //#region src/schemas/fill-in-the-blanks.ts
266
+ // src/schemas/fill-in-the-blanks.ts
272
267
  /**
273
268
  * Matches `{{ blank_id }}` placeholders in a passage, capturing the trimmed id.
274
269
  * Exported for the draft checks in `authoring/`, which must read a passage
@@ -276,6 +271,12 @@ const RedactedMediaSchema = zod_v4.strictObject({
276
271
  */
277
272
  const PLACEHOLDER_RE = /\{\{\s*([^{}]+?)\s*\}\}/g;
278
273
  /**
274
+ * The instructions of an item with a passage: plain text, with no `{{id}}`
275
+ * placeholder. Blanks and gaps live in the passage only, and one written here
276
+ * would be shown to the learner as it stands. Shared by Gap Select.
277
+ */
278
+ const PassageInstructionsSchema = zod_v4.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." });
279
+ /**
279
280
  * Zod schema for a `TextMatchPolicy` — the opt-in matching tolerances a blank
280
281
  * may declare. Every default reproduces the v1 trim + case-fold semantics.
281
282
  */
@@ -323,6 +324,7 @@ const FillInTheBlanksDataSchema = zod_v4.looseObject({
323
324
  type: zod_v4.literal("fill-in-the-blanks"),
324
325
  id: zod_v4.string().min(1),
325
326
  title: zod_v4.string().min(1),
327
+ instructions: PassageInstructionsSchema.optional(),
326
328
  passage: zod_v4.string().min(1),
327
329
  passageHtml: zod_v4.string().optional(),
328
330
  blanks: zod_v4.array(BlankConfigSchema).min(1),
@@ -354,8 +356,7 @@ const FillInTheBlanksDataSchema = zod_v4.looseObject({
354
356
  error: "Each blank id must appear exactly once in blanks[] and have exactly one matching {{id}} placeholder in the passage, and vice versa.",
355
357
  path: ["passage"]
356
358
  });
357
- //#endregion
358
- //#region src/answer-leak.ts
359
+ // src/answer-leak.ts
359
360
  /**
360
361
  * Whether a text gives an answer away: the rule an AI hint is held to, and the
361
362
  * one the item critic holds an author's own hint, title and passage to.
@@ -442,8 +443,7 @@ function revealsAnswer(text, answer, passage, position) {
442
443
  if (before === void 0 && after === void 0) return containsWords(words, needle);
443
444
  return before !== void 0 && containsWords(words, [before, ...needle]) || after !== void 0 && containsWords(words, [...needle, after]);
444
445
  }
445
- //#endregion
446
- //#region src/built-in-types.ts
446
+ // src/built-in-types.ts
447
447
  /**
448
448
  * The activity types the SDK ships, in one closed list.
449
449
  *
@@ -479,8 +479,7 @@ function isBuiltInActivityType(type) {
479
479
  * @internal
480
480
  */
481
481
  function everyBuiltInTypeHandled(_value) {}
482
- //#endregion
483
- //#region src/scoring/dictation/edit-distance.ts
482
+ // src/scoring/dictation/edit-distance.ts
484
483
  /**
485
484
  * The code points of `text`, as numbers. A surrogate pair is one code point; a
486
485
  * lone surrogate iterates as one code point too — deterministic, never thrown.
@@ -532,8 +531,7 @@ function similarity(a, b) {
532
531
  const max = Math.max(codePoints(a).length, codePoints(b).length);
533
532
  return max === 0 ? 0 : (max - editDistance(a, b)) / max;
534
533
  }
535
- //#endregion
536
- //#region src/validation-scope.ts
534
+ // src/validation-scope.ts
537
535
  /**
538
536
  * Work shared for the length of one outermost validation call.
539
537
  *
@@ -572,8 +570,7 @@ function scopeCache(key, create) {
572
570
  }
573
571
  return value;
574
572
  }
575
- //#endregion
576
- //#region src/scoring/dictation/unicode-joining.ts
573
+ // src/scoring/dictation/unicode-joining.ts
577
574
  /**
578
575
  * Unicode data the dictation normaliser reads when it decides whether a joiner
579
576
  * changes how the text is drawn (see `normalize.ts`): the viramas, and which
@@ -791,8 +788,7 @@ const JOINS_BACKWARD = [
791
788
  [69577, 69578],
792
789
  [125184, 125251]
793
790
  ];
794
- //#endregion
795
- //#region src/scoring/dictation/normalize.ts
791
+ // src/scoring/dictation/normalize.ts
796
792
  /**
797
793
  * The longest transcript a dictation accepts, in code points, before and after
798
794
  * its equivalences are applied — and its rules may not grow it past twice
@@ -1752,8 +1748,7 @@ function searchReveal(forms, candidate) {
1752
1748
  return fields.some((field) => containsPhrase(field, phrase));
1753
1749
  });
1754
1750
  }
1755
- //#endregion
1756
- //#region src/scoring/dictation/align.ts
1751
+ // src/scoring/dictation/align.ts
1757
1752
  /**
1758
1753
  * The words the scorer can emit a detail for, one list per candidate — index 0
1759
1754
  * is the transcript, index n is `acceptedTranscripts[n − 1]` — each word in the
@@ -1952,8 +1947,7 @@ function alignWords(reference, attempt) {
1952
1947
  }
1953
1948
  return words;
1954
1949
  }
1955
- //#endregion
1956
- //#region src/errors.ts
1950
+ // src/errors.ts
1957
1951
  /** Thrown when activity data fails schema validation at a component boundary. */
1958
1952
  var ActivitySchemaError = class extends Error {
1959
1953
  activityType;
@@ -2007,8 +2001,7 @@ var DeferredScoringError = class extends Error {
2007
2001
  this.name = "DeferredScoringError";
2008
2002
  }
2009
2003
  };
2010
- //#endregion
2011
- //#region src/schemas/after-issues.ts
2004
+ // src/schemas/after-issues.ts
2012
2005
  /**
2013
2006
  * A check zod runs even when another field was refused. An ordinary check is
2014
2007
  * skipped once any issue has been reported, so an author fixing a recording's
@@ -2045,8 +2038,7 @@ function parsedFields(payload) {
2045
2038
  refused
2046
2039
  };
2047
2040
  }
2048
- //#endregion
2049
- //#region src/schemas/dictation.ts
2041
+ // src/schemas/dictation.ts
2050
2042
  /**
2051
2043
  * Zod schema for the slower second recording of a dictation. Loose like every
2052
2044
  * content schema (a sidecar survives), audio only, and — deliberately — with no
@@ -2228,8 +2220,7 @@ function groupCaptionsField(group, written) {
2228
2220
  }
2229
2221
  /** The message every validator gives for {@link groupCaptionsRevealDictation}. */
2230
2222
  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.";
2231
- //#endregion
2232
- //#region src/authoring/issues.ts
2223
+ // src/authoring/issues.ts
2233
2224
  /**
2234
2225
  * Every issue code the SDK's draft checks can report, with its severity.
2235
2226
  *
@@ -2565,8 +2556,7 @@ function coveredPathsOf(reported) {
2565
2556
  }
2566
2557
  return covered;
2567
2558
  }
2568
- //#endregion
2569
- //#region src/authoring/dictation.ts
2559
+ // src/authoring/dictation.ts
2570
2560
  /**
2571
2561
  * Draft support for `dictation`.
2572
2562
  *
@@ -2756,8 +2746,7 @@ function checkTolerance(tolerance) {
2756
2746
  }
2757
2747
  return issues;
2758
2748
  }
2759
- //#endregion
2760
- //#region src/count-words.ts
2749
+ // src/count-words.ts
2761
2750
  /**
2762
2751
  * Canonical word counter for written-response bounds: tokens are
2763
2752
  * maximal runs of non-whitespace (split on `\s+`), so hyphenated forms
@@ -2862,8 +2851,7 @@ function levelDistribution(values, count, chosen) {
2862
2851
  const sum = read.reduce((total, p) => total + p, 0);
2863
2852
  return Math.abs(sum - 1) <= 1e-6 && read[chosen] === Math.max(...read) ? read : null;
2864
2853
  }
2865
- //#endregion
2866
- //#region src/scoring/strategies/all-or-nothing.ts
2854
+ // src/scoring/strategies/all-or-nothing.ts
2867
2855
  /**
2868
2856
  * All-or-nothing scoring: full credit only when every item is correct.
2869
2857
  *
@@ -2873,8 +2861,7 @@ function levelDistribution(values, count, chosen) {
2873
2861
  function allOrNothingStrategy(correctItems) {
2874
2862
  return correctItems.every((isCorrect) => isCorrect) ? 1 : 0;
2875
2863
  }
2876
- //#endregion
2877
- //#region src/scoring/strategies/partial.ts
2864
+ // src/scoring/strategies/partial.ts
2878
2865
  /**
2879
2866
  * Partial-credit scoring for Multiple Choice — balanced/symmetric scheme.
2880
2867
  *
@@ -2914,8 +2901,7 @@ function partialStrategy(correctSelected, incorrectSelected, totalCorrect, total
2914
2901
  function partialBlankStrategy(correctBlanks, totalBlanks) {
2915
2902
  return correctBlanks / totalBlanks;
2916
2903
  }
2917
- //#endregion
2918
- //#region src/scoring/text-match.ts
2904
+ // src/scoring/text-match.ts
2919
2905
  /** Combining marks (any script) removed for diacritic folding after NFD decomposition. */
2920
2906
  const COMBINING_MARKS_RE = /\p{M}/gu;
2921
2907
  /**
@@ -3008,8 +2994,7 @@ function matchText(input, accepted, policy = {}) {
3008
2994
  via: "none"
3009
2995
  };
3010
2996
  }
3011
- //#endregion
3012
- //#region src/scoring/activity-scorers/fill-in-the-blanks.ts
2997
+ // src/scoring/activity-scorers/fill-in-the-blanks.ts
3013
2998
  /**
3014
2999
  * Resolves the effective match policy for a blank. The legacy
3015
3000
  * `caseSensitive` / `trimWhitespace` flags map onto the baseline policy
@@ -3053,8 +3038,7 @@ function scoreFillInTheBlanks(data, response) {
3053
3038
  details
3054
3039
  };
3055
3040
  }
3056
- //#endregion
3057
- //#region src/authoring/findings.ts
3041
+ // src/authoring/findings.ts
3058
3042
  /**
3059
3043
  * Every finding code the SDK's item critic can report, with its severity.
3060
3044
  *
@@ -3107,8 +3091,7 @@ function normaliseFinding(found) {
3107
3091
  severity: documented ?? (found.severity === "advice" ? "advice" : "warning")
3108
3092
  };
3109
3093
  }
3110
- //#endregion
3111
- //#region src/authoring/critique.ts
3094
+ // src/authoring/critique.ts
3112
3095
  /**
3113
3096
  * The built-in item critic: what an experienced item writer points out on
3114
3097
  * review, as far as a rule can see it without a model.
@@ -3391,8 +3374,7 @@ function keyPositionFinding(items, path) {
3391
3374
  if (positions.length < KEY_POSITION_MINIMUM || !positions.every((at) => at === positions[0])) return [];
3392
3375
  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.`)];
3393
3376
  }
3394
- //#endregion
3395
- //#region src/authoring/fill-in-the-blanks.ts
3377
+ // src/authoring/fill-in-the-blanks.ts
3396
3378
  /**
3397
3379
  * Draft support for `fill-in-the-blanks`.
3398
3380
  *
@@ -3524,8 +3506,7 @@ function pairsOneToOne$1(placeholders, blanks) {
3524
3506
  if (placeholders.size !== blankIds.length) return false;
3525
3507
  return blankIds.every((id) => typeof id === "string" && placeholders.get(id) === 1);
3526
3508
  }
3527
- //#endregion
3528
- //#region src/authoring/gap-select.ts
3509
+ // src/authoring/gap-select.ts
3529
3510
  /** Mirrors `GapSelectChoiceSchema` arrays: `.min(2)` on both a gap's own list and a bank. */
3530
3511
  const MIN_CHOICES = 2;
3531
3512
  /**
@@ -3723,8 +3704,7 @@ function pairsOneToOne(placeholders, gaps) {
3723
3704
  if (new Set(ids).size !== ids.length || placeholders.size !== ids.length) return false;
3724
3705
  return ids.every((id) => typeof id === "string" && placeholders.get(id) === 1);
3725
3706
  }
3726
- //#endregion
3727
- //#region src/schemas/multiple-choice.ts
3707
+ // src/schemas/multiple-choice.ts
3728
3708
  /**
3729
3709
  * Zod schema for a single Multiple Choice option. Loose: unknown keys are
3730
3710
  * preserved through validation (forward-compat / consumer sidecars — B7).
@@ -3788,6 +3768,7 @@ const MultipleChoiceDataSchema = zod_v4.looseObject({
3788
3768
  type: zod_v4.literal("multiple-choice"),
3789
3769
  id: zod_v4.string().min(1),
3790
3770
  title: zod_v4.string().min(1),
3771
+ instructions: zod_v4.string().optional(),
3791
3772
  question: zod_v4.string().min(1),
3792
3773
  questionHtml: zod_v4.string().optional(),
3793
3774
  mode: zod_v4.enum(["single", "multi"]),
@@ -3817,8 +3798,7 @@ const MultipleChoiceDataSchema = zod_v4.looseObject({
3817
3798
  error: "Option ids must be unique within the activity.",
3818
3799
  path: ["options"]
3819
3800
  });
3820
- //#endregion
3821
- //#region src/authoring/multiple-choice.ts
3801
+ // src/authoring/multiple-choice.ts
3822
3802
  /** Mirrors `MultipleChoiceDataSchema`: `options` is `.min(2).max(26)`. */
3823
3803
  const MIN_OPTIONS = 2;
3824
3804
  const MAX_OPTIONS = 26;
@@ -3921,8 +3901,7 @@ function checkOptionMedia(media, index, ordinal) {
3921
3901
  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.`)];
3922
3902
  return checkMedia(media, path, MultipleChoiceOptionMediaSchema);
3923
3903
  }
3924
- //#endregion
3925
- //#region src/scoring/speech/limits.ts
3904
+ // src/scoring/speech/limits.ts
3926
3905
  /**
3927
3906
  * The longest reference text a read-aloud item accepts, in code points, before
3928
3907
  * and after normalisation. It is the dictation transcript cap on purpose: the
@@ -3972,8 +3951,7 @@ const SPEECH_ASSESSMENT_MAX_WORDS = 1e3;
3972
3951
  * read-aloud item comes near it.
3973
3952
  */
3974
3953
  const SPEECH_ASSESSMENT_MAX_TEXT_LENGTH = DICTATION_MAX_TEXT_LENGTH;
3975
- //#endregion
3976
- //#region src/scoring/speech/locale.ts
3954
+ // src/scoring/speech/locale.ts
3977
3955
  /**
3978
3956
  * A BCP 47 tag in the one spelling read-aloud accepts: a lowercase language of
3979
3957
  * two or three letters, an optional title-case script, and a region of two
@@ -3989,8 +3967,7 @@ const SPEECH_ASSESSMENT_MAX_TEXT_LENGTH = DICTATION_MAX_TEXT_LENGTH;
3989
3967
  * Internal: the content schema and the assessment validator share it.
3990
3968
  */
3991
3969
  const CANONICAL_LOCALE_RE = /^[a-z]{2,3}(?:-[A-Z][a-z]{3})?-(?:[A-Z]{2}|[0-9]{3})$/;
3992
- //#endregion
3993
- //#region src/schemas/read-aloud.ts
3970
+ // src/schemas/read-aloud.ts
3994
3971
  /** The dimensions a read-aloud grade can be made of, in the order they are documented. */
3995
3972
  const READ_ALOUD_DIMENSIONS = [
3996
3973
  "accuracy",
@@ -4143,8 +4120,7 @@ const ReadAloudDataSchema = zod_v4.looseObject({
4143
4120
  if (minSeconds !== void 0 && minSeconds >= maxSeconds) report(["recording", "minSeconds"], minSeconds, "The shortest take must be shorter than the longest.");
4144
4121
  }
4145
4122
  }));
4146
- //#endregion
4147
- //#region src/authoring/read-aloud.ts
4123
+ // src/authoring/read-aloud.ts
4148
4124
  /**
4149
4125
  * Draft support for `read-aloud`.
4150
4126
  *
@@ -4307,8 +4283,7 @@ function checkSlowRecording(draft) {
4307
4283
  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."));
4308
4284
  return issues;
4309
4285
  }
4310
- //#endregion
4311
- //#region src/authoring/written-response.ts
4286
+ // src/authoring/written-response.ts
4312
4287
  /**
4313
4288
  * Draft support for `written-response`.
4314
4289
  *
@@ -4396,8 +4371,7 @@ function checkCriteria(criteria) {
4396
4371
  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."));
4397
4372
  return issues;
4398
4373
  }
4399
- //#endregion
4400
- //#region src/schemas/gap-select.ts
4374
+ // src/schemas/gap-select.ts
4401
4375
  /**
4402
4376
  * Zod schema for one selectable choice. Loose, like every other schema here:
4403
4377
  * unknown keys are preserved so a consumer sidecar survives validation.
@@ -4461,6 +4435,7 @@ const GapSelectDataSchema = zod_v4.looseObject({
4461
4435
  type: zod_v4.literal("gap-select"),
4462
4436
  id: zod_v4.string().min(1),
4463
4437
  title: zod_v4.string().min(1),
4438
+ instructions: PassageInstructionsSchema.optional(),
4464
4439
  passage: zod_v4.string().min(1),
4465
4440
  passageHtml: zod_v4.string().optional(),
4466
4441
  gaps: zod_v4.array(GapSelectGapSchema).min(1),
@@ -4521,8 +4496,7 @@ const GapSelectDataSchema = zod_v4.looseObject({
4521
4496
  error: "Each gap needs unique choice ids and a `correctChoiceId` that is one of the choices it offers.",
4522
4497
  path: ["gaps"]
4523
4498
  });
4524
- //#endregion
4525
- //#region src/schemas/written-response.ts
4499
+ // src/schemas/written-response.ts
4526
4500
  /** Zod schema for a single rubric criterion. Loose: unknown keys preserved. */
4527
4501
  const WrittenResponseRubricCriterionSchema = zod_v4.looseObject({
4528
4502
  name: zod_v4.string().min(1),
@@ -4593,8 +4567,7 @@ const WrittenResponseDataSchema = zod_v4.looseObject({
4593
4567
  error: "maxWords must be greater than or equal to minWords.",
4594
4568
  path: ["maxWords"]
4595
4569
  });
4596
- //#endregion
4597
- //#region src/schemas/redacted.ts
4570
+ // src/schemas/redacted.ts
4598
4571
  /**
4599
4572
  * Schemas for REDACTED activity data — the learner-safe projection `redact()`
4600
4573
  * produces (R7). Deliberately STRICT (`z.strictObject`), the opposite of the
@@ -4658,6 +4631,7 @@ const RedactedMultipleChoiceOptionSchema = zod_v4.strictObject({
4658
4631
  const RedactedMultipleChoiceDataSchema = zod_v4.strictObject({
4659
4632
  ...redactedBase,
4660
4633
  type: zod_v4.literal("multiple-choice"),
4634
+ instructions: zod_v4.string().optional(),
4661
4635
  question: zod_v4.string().min(1),
4662
4636
  questionHtml: zod_v4.string().optional(),
4663
4637
  mode: zod_v4.enum(["single", "multi"]),
@@ -4673,6 +4647,7 @@ const RedactedBlankConfigSchema = zod_v4.strictObject({
4673
4647
  const RedactedFillInTheBlanksDataSchema = zod_v4.strictObject({
4674
4648
  ...redactedBase,
4675
4649
  type: zod_v4.literal("fill-in-the-blanks"),
4650
+ instructions: zod_v4.string().optional(),
4676
4651
  passage: zod_v4.string().min(1),
4677
4652
  passageHtml: zod_v4.string().optional(),
4678
4653
  blanks: zod_v4.array(RedactedBlankConfigSchema).min(1)
@@ -4711,6 +4686,7 @@ const RedactedGapSelectGapSchema = zod_v4.strictObject({
4711
4686
  const RedactedGapSelectDataSchema = zod_v4.strictObject({
4712
4687
  ...redactedBase,
4713
4688
  type: zod_v4.literal("gap-select"),
4689
+ instructions: zod_v4.string().optional(),
4714
4690
  passage: zod_v4.string().min(1),
4715
4691
  passageHtml: zod_v4.string().optional(),
4716
4692
  gaps: zod_v4.array(RedactedGapSelectGapSchema).min(1),
@@ -4836,8 +4812,7 @@ const RedactedReadAloudDataSchema = zod_v4.strictObject({
4836
4812
  path: ["slowMedia", "url"]
4837
4813
  });
4838
4814
  });
4839
- //#endregion
4840
- //#region src/scoring/activity-scorers/dictation.ts
4815
+ // src/scoring/activity-scorers/dictation.ts
4841
4816
  /**
4842
4817
  * Scores a Dictation response: the character-level similarity of what the
4843
4818
  * learner typed to the transcript, over the whole sentence.
@@ -4876,8 +4851,7 @@ function scoreDictation(data, response) {
4876
4851
  details
4877
4852
  };
4878
4853
  }
4879
- //#endregion
4880
- //#region src/scoring/activity-scorers/gap-select.ts
4854
+ // src/scoring/activity-scorers/gap-select.ts
4881
4855
  /**
4882
4856
  * The choices a gap offers: its own list, or the bank it names.
4883
4857
  *
@@ -4931,8 +4905,7 @@ function scoreGapSelect(data, response) {
4931
4905
  details
4932
4906
  };
4933
4907
  }
4934
- //#endregion
4935
- //#region src/scoring/activity-scorers/multiple-choice.ts
4908
+ // src/scoring/activity-scorers/multiple-choice.ts
4936
4909
  /**
4937
4910
  * Scores a Multiple Choice response. Pure; trusts its typed inputs (validation
4938
4911
  * is the component boundary's job). Options are looked up by id; an unknown
@@ -4976,8 +4949,7 @@ function scoreMultipleChoice(data, response) {
4976
4949
  details
4977
4950
  };
4978
4951
  }
4979
- //#endregion
4980
- //#region src/registry/define.ts
4952
+ // src/registry/define.ts
4981
4953
  /**
4982
4954
  * Identity helper that gives full type inference when authoring a descriptor:
4983
4955
  *
@@ -4992,8 +4964,7 @@ function scoreMultipleChoice(data, response) {
4992
4964
  function defineActivityType(descriptor) {
4993
4965
  return descriptor;
4994
4966
  }
4995
- //#endregion
4996
- //#region src/registry/keep-when.ts
4967
+ // src/registry/keep-when.ts
4997
4968
  /**
4998
4969
  * A nested field policy that keeps its field only when the field's value
4999
4970
  * passes a test. Internal: the symbol is never exported, so no host policy can
@@ -5018,8 +4989,7 @@ function keepWhen(policy, test) {
5018
4989
  function guardOf(policy) {
5019
4990
  return policy[KEEP_WHEN];
5020
4991
  }
5021
- //#endregion
5022
- //#region src/registry/builtins.ts
4992
+ // src/registry/builtins.ts
5023
4993
  /**
5024
4994
  * Where the built-in types keep their files (`mediaSlots`). Every type has its
5025
4995
  * `media`; dictation and read-aloud add a slower recording; a multiple-choice
@@ -5137,6 +5107,7 @@ const TEXT_MATCH_FIELD_POLICY = {
5137
5107
  };
5138
5108
  const MULTIPLE_CHOICE_FIELD_POLICY = {
5139
5109
  ...SHARED_PUBLIC_FIELDS,
5110
+ instructions: "public",
5140
5111
  question: "public",
5141
5112
  questionHtml: "public",
5142
5113
  mode: "public",
@@ -5171,6 +5142,7 @@ const MULTIPLE_CHOICE_FIELD_POLICY = {
5171
5142
  */
5172
5143
  const GAP_SELECT_FIELD_POLICY = {
5173
5144
  ...SHARED_PUBLIC_FIELDS,
5145
+ instructions: "public",
5174
5146
  passage: "public",
5175
5147
  passageHtml: "public",
5176
5148
  presentation: "public",
@@ -5197,6 +5169,7 @@ const GAP_SELECT_FIELD_POLICY = {
5197
5169
  };
5198
5170
  const FILL_IN_THE_BLANKS_FIELD_POLICY = {
5199
5171
  ...SHARED_PUBLIC_FIELDS,
5172
+ instructions: "public",
5200
5173
  passage: "public",
5201
5174
  passageHtml: "public",
5202
5175
  scoringStrategy: "answer-key",
@@ -5499,8 +5472,7 @@ const BUILT_IN_DESCRIPTORS = {
5499
5472
  dictation: dictationType,
5500
5473
  "read-aloud": readAloudType
5501
5474
  };
5502
- //#endregion
5503
- //#region src/schemas/read-schema.ts
5475
+ // src/schemas/read-schema.ts
5504
5476
  /**
5505
5477
  * How every entry point reads a schema — `validateActivity`, `validateDraft`,
5506
5478
  * `validateItemGroup`, `redact`, `assertRedacted` — so a schema is read one way
@@ -5616,8 +5588,7 @@ function standardJsonSchemaOf(schema, target = "draft-07") {
5616
5588
  const generated = converter.output({ target });
5617
5589
  return generated !== null && typeof generated === "object" && !Array.isArray(generated) ? generated : void 0;
5618
5590
  }
5619
- //#endregion
5620
- //#region src/registry/registry.ts
5591
+ // src/registry/registry.ts
5621
5592
  /**
5622
5593
  * Module-scoped default registry (deliberate — no registry instances until a
5623
5594
  * second consumer exists), created holding the SDK's own types.
@@ -5663,7 +5634,6 @@ function getActivityTypeDescriptor(type) {
5663
5634
  function registeredActivityTypes() {
5664
5635
  return [...registry.keys()];
5665
5636
  }
5666
- //#endregion
5667
5637
  Object.defineProperty(exports, "ActivitySchemaError", {
5668
5638
  enumerable: true,
5669
5639
  get: function() {
@@ -6157,4 +6127,4 @@ Object.defineProperty(exports, "writtenResponseType", {
6157
6127
  }
6158
6128
  });
6159
6129
 
6160
- //# sourceMappingURL=registry-Ih5n4PVZ.cjs.map
6130
+ //# sourceMappingURL=registry-hzrkTeIT.cjs.map