@intellectif/lk-core 1.1.0 → 1.3.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 (99) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +4 -3
  3. package/dist/ai-B222dtHH.d.cts +2154 -0
  4. package/dist/ai-B222dtHH.d.cts.map +1 -0
  5. package/dist/ai-B222dtHH.d.ts +2154 -0
  6. package/dist/ai-B222dtHH.d.ts.map +1 -0
  7. package/dist/ai-check.cjs +758 -464
  8. package/dist/ai-check.cjs.map +1 -1
  9. package/dist/ai-check.d.cts +82 -68
  10. package/dist/ai-check.d.cts.map +1 -0
  11. package/dist/ai-check.d.ts +82 -68
  12. package/dist/ai-check.d.ts.map +1 -0
  13. package/dist/ai-check.js +756 -465
  14. package/dist/ai-check.js.map +1 -1
  15. package/dist/ai-writing-CCBjTOM3.js +2496 -0
  16. package/dist/ai-writing-CCBjTOM3.js.map +1 -0
  17. package/dist/ai-writing-DCVkv4Zj.cjs +2735 -0
  18. package/dist/ai-writing-DCVkv4Zj.cjs.map +1 -0
  19. package/dist/{index-DlcqkM_L.d.ts → index-BWPRPIXL.d.ts} +263 -258
  20. package/dist/index-BWPRPIXL.d.ts.map +1 -0
  21. package/dist/index-CXyOV8sm.d.cts +153 -0
  22. package/dist/index-CXyOV8sm.d.cts.map +1 -0
  23. package/dist/index-CegM8o15.d.ts +153 -0
  24. package/dist/index-CegM8o15.d.ts.map +1 -0
  25. package/dist/index-Dyu66R4-.d.cts +1071 -0
  26. package/dist/index-Dyu66R4-.d.cts.map +1 -0
  27. package/dist/{index-DlCW0XaQ.d.cts → index-O4_ExlAD.d.cts} +263 -258
  28. package/dist/index-O4_ExlAD.d.cts.map +1 -0
  29. package/dist/index-UGxRSopE.d.ts +1071 -0
  30. package/dist/index-UGxRSopE.d.ts.map +1 -0
  31. package/dist/index.cjs +1210 -1671
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +1090 -853
  34. package/dist/index.d.cts.map +1 -0
  35. package/dist/index.d.ts +1090 -853
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +1063 -1672
  38. package/dist/index.js.map +1 -1
  39. package/dist/item-group-DXiR8nOr.js +445 -0
  40. package/dist/item-group-DXiR8nOr.js.map +1 -0
  41. package/dist/item-group-DroFXgLb.cjs +505 -0
  42. package/dist/item-group-DroFXgLb.cjs.map +1 -0
  43. package/dist/registry-DVi0LR_i.cjs +5915 -0
  44. package/dist/registry-DVi0LR_i.cjs.map +1 -0
  45. package/dist/registry-Dsx9mNsS.js +5449 -0
  46. package/dist/registry-Dsx9mNsS.js.map +1 -0
  47. package/dist/schemas-Bdw0nGPo.js +152 -0
  48. package/dist/schemas-Bdw0nGPo.js.map +1 -0
  49. package/dist/schemas-DVbAOrtd.cjs +224 -0
  50. package/dist/schemas-DVbAOrtd.cjs.map +1 -0
  51. package/dist/schemas.cjs +16 -32
  52. package/dist/schemas.d.cts +2 -2
  53. package/dist/schemas.d.ts +2 -2
  54. package/dist/schemas.js +3 -32
  55. package/dist/scoring-B2_HEhMT.cjs +1748 -0
  56. package/dist/scoring-B2_HEhMT.cjs.map +1 -0
  57. package/dist/scoring-BZqUkuDF.js +1604 -0
  58. package/dist/scoring-BZqUkuDF.js.map +1 -0
  59. package/dist/scoring.cjs +37 -75
  60. package/dist/scoring.d.cts +3 -1103
  61. package/dist/scoring.d.ts +3 -1103
  62. package/dist/scoring.js +3 -75
  63. package/dist/xapi-CMTph7wG.js +332 -0
  64. package/dist/xapi-CMTph7wG.js.map +1 -0
  65. package/dist/xapi-DNzkSJ0S.cjs +362 -0
  66. package/dist/xapi-DNzkSJ0S.cjs.map +1 -0
  67. package/dist/xapi.cjs +7 -16
  68. package/dist/xapi.d.cts +2 -150
  69. package/dist/xapi.d.ts +2 -150
  70. package/dist/xapi.js +2 -16
  71. package/package.json +4 -4
  72. package/dist/activity-MBOYLBjR.d.cts +0 -1840
  73. package/dist/activity-MBOYLBjR.d.ts +0 -1840
  74. package/dist/chunk-2JT2WUQ2.cjs +0 -458
  75. package/dist/chunk-2JT2WUQ2.cjs.map +0 -1
  76. package/dist/chunk-DSDXL3JO.cjs +0 -4597
  77. package/dist/chunk-DSDXL3JO.cjs.map +0 -1
  78. package/dist/chunk-FBKTION6.js +0 -4597
  79. package/dist/chunk-FBKTION6.js.map +0 -1
  80. package/dist/chunk-IARLJ5MW.js +0 -1256
  81. package/dist/chunk-IARLJ5MW.js.map +0 -1
  82. package/dist/chunk-LDFQUZII.cjs +0 -950
  83. package/dist/chunk-LDFQUZII.cjs.map +0 -1
  84. package/dist/chunk-NQHETFDA.js +0 -950
  85. package/dist/chunk-NQHETFDA.js.map +0 -1
  86. package/dist/chunk-SJVRUPJT.js +0 -272
  87. package/dist/chunk-SJVRUPJT.js.map +0 -1
  88. package/dist/chunk-TJJFKKH2.cjs +0 -272
  89. package/dist/chunk-TJJFKKH2.cjs.map +0 -1
  90. package/dist/chunk-VSH7ECQL.cjs +0 -1256
  91. package/dist/chunk-VSH7ECQL.cjs.map +0 -1
  92. package/dist/chunk-XS6U2ARZ.js +0 -458
  93. package/dist/chunk-XS6U2ARZ.js.map +0 -1
  94. package/dist/schemas.cjs.map +0 -1
  95. package/dist/schemas.js.map +0 -1
  96. package/dist/scoring.cjs.map +0 -1
  97. package/dist/scoring.js.map +0 -1
  98. package/dist/xapi.cjs.map +0 -1
  99. package/dist/xapi.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @intellectif/lk-core
2
2
 
3
+ ## 1.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#90](https://github.com/intellectif/learning-kit/pull/90) [`9b5f5ef`](https://github.com/intellectif/learning-kit/commit/9b5f5ef6243f825c1336628d38816789993455b3) Thanks [@diego28e](https://github.com/diego28e)! - **Smaller bundles, one list of built-in types, and two deprecations**: importing one function from lk-core no longer bundles all of zod.
8
+
9
+ **Action required:** none. Two things are deprecated and keep working throughout 1.x: a fill-in-the-blanks blank's `caseSensitive` / `trimWhitespace` (write `match: { caseSensitive, trim }`), and `seededShuffle` without a `version` (write `{ version: 1 }` to keep an order already recorded).
10
+
11
+ - **Smaller bundles.** An app that imports only `score`, or only `xAPIBuilder` from `/xapi`, used to bundle every one of zod's 60-odd locales: about 121 kB gzipped for `{ score }`. It is now about 54 kB. Grades, validation results and error messages are unchanged — every grade vector and validation expectation replays identically — and new size budgets hold lk-core to it.
12
+ - **`BUILT_IN_ACTIVITY_TYPES`, `BuiltInActivityType` and `isBuiltInActivityType`** name the types the SDK ships. `ActivityType` cannot, since a host's module augmentation widens it: use these to tell your own registered types from the SDK's.
13
+ - **`hintRevealsAnswer` withholds a hint it cannot check.** Given facts of a kind it cannot read, it now answers `true` — the hint reveals — where it answered `false` and let the hint through. No built-in type reaches that case today; a new one would have.
14
+ - **The built-in types are registered however your bundler splits lk-core.** They were registered as a module loaded, which held only because the build put that module beside the lookups; lk-core declares `sideEffects: false`, so a bundler may drop such a module. The registry is now created holding them.
15
+ - **Deprecated, still working throughout 1.x:** a blank's `caseSensitive` and `trimWhitespace` (`match.caseSensitive` and `match.trim` mean the same), and calling `seededShuffle` without `version` — it still draws version 1, but a 2.0 may make version 2 the default. See [Stability](https://github.com/intellectif/learning-kit/blob/main/docs/stability.md#deprecation).
16
+ - **Built with tsdown**, as tsup is no longer maintained. Every entry point exports the same names in ESM and CommonJS, the declarations describe the same API, and the grade and validation corpora replay identically; only the names of the internal chunk files differ.
17
+
18
+ ## 1.2.0
19
+
20
+ ### Minor Changes
21
+
22
+ - [#88](https://github.com/intellectif/learning-kit/pull/88) [`493dd06`](https://github.com/intellectif/learning-kit/commit/493dd0648a73c7f47d889683bc9f7f08d8a0acc9) Thanks [@diego28e](https://github.com/diego28e)! - **Assistants for authors**: an item critic, a model's review of an item, and drafts from a passage, a transcript or a video's captions.
23
+
24
+ **Action required:** none unless your code switches over `AiRefusal` without a `default` branch (new member `'contradicts-item'`) or reads `AiCheckCase.request` without narrowing on `feature` (new `'item-critique'` and `'draft-generation'` cases). Nothing runs until you call it, no grade changes, and there is no lk-react release: lk-react 23.1 works with it as it is. See https://github.com/intellectif/learning-kit/blob/main/docs/upgrading.md
25
+
26
+ - **The item critic:** `critiqueDraft(type, draft)`, `critiqueDrafts(entries)` for a question set and `critiqueItemGroupDraft(group)` for a testlet point out what a reviewer would on an item that may be perfectly valid — a title, hint or passage that prints the answer, two options that read the same, the right option much longer than the rest, "all of the above" under shuffle, a word bank with no distractor, a text too long for its recording time, every right option in one position. Findings are `warning` or `advice`, in `DraftIssue`'s shape so an editor lists both, and never change what `validateDraft` says. Seventeen codes, documented with their rules: https://github.com/intellectif/learning-kit/blob/main/docs/authoring.md
27
+ - **A registered type** joins the critic through a new optional `authoring.critique`.
28
+ - **A model's review:** `aiCritiqueRequest` gives a model the item, every text field it may point at, and the critic's own findings; `checkAiCritique` lists its findings as `advice`, and refuses the whole reply as `contradicts-item` when a finding points at a field the item does not have or quotes words that field does not hold.
29
+ - **Drafts from a source:** `aiDraftsRequest` takes the types an author ticks — multiple choice, fill in the blanks, gap select, dictation, read-aloud, written response — in the author's order, an optional count (left out, as many as the source is worth, up to 50), the author's own instructions and your settings per type, and gives the model the JSON Schema of a reply: each type's own fields, no ids, HTML, media, switches or scoring settings; `checkAiDrafts` makes drafts with your ids and settings, in the author's order, each checked by `validateDraft` and the critic — from captions placed where its caption ends, a dictation with the stretch of video that says it; `aiDraftsRepairRequest` sends back what is unfinished, wrong or warned about; `generateDrafts` runs that loop, once by default and three times at most, and never throws for a model's failure. A draft is never approved by the SDK. https://github.com/intellectif/learning-kit/blob/main/docs/ai.md
30
+ - **A video's quizzes:** `interactiveVideoFromDrafts` makes the drafts an interactive video — each question where its caption ends, questions at one moment in the author's order, and every question without a moment in one quiz at the end of the video (`durationSeconds`).
31
+ - **ai-check:** a `critique` port runs four review cases and a `drafts` port six drafting cases, two of them video quizzes.
32
+
3
33
  ## 1.1.0
4
34
 
5
35
  ### Minor Changes
package/README.md CHANGED
@@ -19,6 +19,7 @@ npm install @intellectif/lk-core
19
19
  - **`validateActivity(type, data)`** — the authoritative runtime validator. Returns a typed `{ success, data }` or a structured `{ success: false, errors[] }`, and **throws `UnknownActivityTypeError` if `type` is not registered** — so guard it when validating a content bank that may carry types this build does not know. `validateItemGroup(data)` is the equivalent for a `Stimulus` + `ItemGroup` container, which `validateActivity` cannot take.
20
20
  - **`validateDraft(type, draft)`** — for editors. Reports `complete`, `incomplete` (something not written yet) or `invalid` (something wrong), each issue with a `severity` and a `code` — documented for every problem the checks recognise — and deliberately no `success` boolean to misread. Stricter than `validateActivity`, never looser. **`createDraft(type, { newId })`** returns an empty draft to start from; a multiple-choice draft marks no option correct.
21
21
  - **An open type system** — `defineActivityType` / `registerActivityType` make an activity type a *value*, not a hard-coded union member: register one and `validateActivity`, `validateDraft`, `score`, `evaluate`, `redact` and `jsonSchemaFor` all work for it, with no SDK release. An `authoring` block on the descriptor gives it draft support.
22
+ - **An item critic** — `critiqueDraft(type, draft)` (and `critiqueDrafts` for a question set, `critiqueItemGroupDraft` for a testlet) points out what a reviewer would on an item that may be perfectly valid: the right option much longer than the rest, an answer printed in the passage, a hint that gives it away, "all of the above" under shuffle. A finding is `warning` or `advice`, in `DraftIssue`'s shape, and never refuses an item.
22
23
  - **JSON Schema (Draft-7) export** — `jsonSchemaFor(type)` for any registered type (plus the static per-type exports), suitable for form generators or AI prompting.
23
24
  - **Scoring engine** — `score(activityType, data, response)` returning `{ score ∈ [0,1], maxScore: 1, passed, feedback, details }`. Pure, deterministic, 100 % test coverage enforced. It **throws** rather than inventing a number: `DeferredScoringError` for a deferred-graded type (`written-response`), and `RedactedScoringError` when handed a `redact()` projection, which has no answer key. Both are on the documented exam path — use `evaluate()` there, which returns `deferred` / `unscorable` instead of throwing.
24
25
  - **Dictation marking as data** — a dictation is graded by the character-level similarity of the typed text to the transcript, with one `ScoringDetail` per word carrying its own `score`. `alignDictation(data, text)` returns the same comparison the grade was made of (normalised strings, word pairings, which accepted transcript won), `diffDictationChars(reference, attempt)` the character-level edits for a marked display, and `dictationReferenceWords(data)` the ids and words a stored result can be checked against — so a review screen or an analytics job never re-implements the arithmetic. `score()` and `evaluate()` take an optional `{ rounding }` to compare the pass line as displayed.
@@ -28,7 +29,7 @@ npm install @intellectif/lk-core
28
29
  - **Item groups** — `Stimulus` + `ItemGroup` (one passage or recording serving several questions), `flattenSequence()` for seeded, shuffle-atomic presentation order with stable slot identity. Slot ids are positional by default (`"3"`, `"1.0"`); author a `slotKey` on an entry and its id survives an insert, so a stored response cannot slide onto a different question.
29
30
  - **Delivery policies** — `DeliveryPolicy` says what a school lets a learner see around a question: feedback, solutions, hints and AI help. `resolveDeliveryPolicy` spells one out (an unreadable setting restricts, never allows), `validateDeliveryPolicy` checks one before it is stored, and `combineDeliveryPolicies` keeps a setting on only where every policy leaves it on.
30
31
  - **Scoring policies** — `ItemScoringPolicy` says how a paper's questions are scored when a learner can try again or ask for hints: `retries`, which try `counts`, and what a try and a hint cost. `scoreTries` does the arithmetic, `evaluate(…, { scoring })` and `evaluateTries` reach a question's outcome from its answers, and `validateItemScoringPolicy` / `resolveItemScoringPolicy` refuse a policy that cannot be applied rather than guess — every setting moves a grade. No policy changes nothing, and the arithmetic is pinned by the grade vectors.
31
- - **AI help contracts** — the SDK calls no model; it builds what yours is given and checks what comes back. `aiExplanationRequest`, `aiHintRequest`, `aiWritingFeedbackRequest` and `aiCoachingRequest` build the requests a component makes, so a server can rebuild them from its own copy of an item; `checkAiExplanation`, `checkAiHint`, `checkAiWritingFeedback` and `checkAiCoaching` refuse an explanation that contradicts the grade, a hint that contains the answer, writing feedback that corrects words the learner never wrote, and coaching on a reading that names a word the speech engine did not mark or a sound it did not report; `checkAiWritingFeedback` computes the rubric's indicative score itself.
32
+ - **AI help contracts** — the SDK calls no model; it builds what yours is given and checks what comes back. `aiExplanationRequest`, `aiHintRequest`, `aiWritingFeedbackRequest` and `aiCoachingRequest` build the requests a component makes, so a server can rebuild them from its own copy of an item; `checkAiExplanation`, `checkAiHint`, `checkAiWritingFeedback` and `checkAiCoaching` refuse an explanation that contradicts the grade, a hint that contains the answer, writing feedback that corrects words the learner never wrote, and coaching on a reading that names a word the speech engine did not mark or a sound it did not report; `checkAiWritingFeedback` computes the rubric's indicative score itself. For authors, `aiCritiqueRequest` / `checkAiCritique` give a model's review of an item, whose every finding must point at the item's own fields, and `aiDraftsRequest` / `checkAiDrafts` / `generateDrafts` draft the types an author ticks, in the author's order, from a passage, a script or captions — each checked by `validateDraft`, critiqued, repaired in a bounded loop, and never approved by the SDK — and `interactiveVideoFromDrafts` makes them a video's quizzes, each question where its caption ends or at the end.
32
33
  - **Attempt plans** — `planAttempt(entries, { seed, shuffleEntries, points, delivery })` freezes the exact paper a learner sat, and the delivery policy it was sat under: slot order, per-slot points, a content hash of each item, and a `planHash` over the lot. `verifyAttemptPlan(plan, current)` reports the drift when that content is later edited (`changedSlotIds`, `changedStimulusSlotIds`, `changedPointsSlotIds`, `missingSlotIds`, …) — the thing you need during a remark or an appeal. `scoredItemsFromPlan(plan, outcomes)` turns collected outcomes into the `ScoredItem[]` composition wants, and defaults a slot with **no** outcome to `deferred` rather than silently shrinking the denominator.
33
34
  - **Attempt state** — `serializeAttemptState(plan, progress)` / `restoreAttemptState(plan, snapshot)` round-trip an interrupted attempt (responses, submitted slots, position) and are **bound to the plan**: restoring answers onto a paper the learner never sat throws instead of succeeding quietly. `diffResponses(before, after)` reports what moved between two snapshots, including an answer the learner *cleared*.
34
35
  - **Media playback policy** — `media.playback` on an audio recording: `maxPlays`, `seek`, `rate`, and advisory `nativeControlHints`. `resolvePlaybackPolicy()` derives the defaults once so the schema, the plan and the renderer cannot drift. Budgets are frozen into the plan by `planAttempt`, so editing `maxPlays` mid-window cannot change what a past learner was held to, and `planAttempt` refuses a paper where one recording is budgeted under two keys.
@@ -132,7 +133,7 @@ Zod is the single runtime dependency, pinned to one exact version and private: n
132
133
  - **What is supported, and since when** — [Features](https://github.com/intellectif/learning-kit/blob/main/docs/features.md): every activity and capability, the `lk-core` / `lk-react` versions it arrived in, and its guide.
133
134
  - **What changed** — [GitHub Releases](https://github.com/intellectif/learning-kit/releases), one per package version, and the same notes in each package's `CHANGELOG.md` (it ships in the npm package, so it is in your `node_modules` too). Notes written since release notes gained a template — every release after lk-core 0.20.0 / lk-react 20.0.0 — start with a one-line summary and **Action required**: `none`, or what to do. Earlier notes lead with the detail; the version map in the upgrading guide says what each one asks of you.
134
135
  - **How to upgrade** — [Upgrading](https://github.com/intellectif/learning-kit/blob/main/docs/upgrading.md): which `lk-core` goes with which `lk-react`, and a section per release saying what, if anything, you need to change. A `lk-react` major is often only the `lk-core` peer bump; the map says so.
135
- - **Hearing about a release** — on GitHub, **Watch → Custom → Releases**, or subscribe to [the releases feed](https://github.com/intellectif/learning-kit/releases.atom). Better still, let your dependency bot bring each release to you as a pull request, with its notes — and keep the two packages together in one, since they move together:
136
+ - **Hearing about a release** — on GitHub, **Watch → Custom → Releases**, or subscribe to [the releases feed](https://github.com/intellectif/learning-kit/releases.atom). Better still, let your dependency bot bring each release to you as a pull request, with its notes — and keep the two packages together in one, since a `lk-react` release names the `lk-core` it needs:
136
137
 
137
138
  ```yaml
138
139
  # .github/dependabot.yml — one entry per directory with a package.json
@@ -148,7 +149,7 @@ Zod is the single runtime dependency, pinned to one exact version and private: n
148
149
 
149
150
  With Renovate: `"packageRules": [{ "matchPackageNames": ["@intellectif/lk-core", "@intellectif/lk-react"], "groupName": "learning-kit" }]`.
150
151
 
151
- `lk-core` is still `0.x`, and a caret range on a `0.x` version matches only that minor: `^0.18.0` never installs `0.19.0`. A bot is how you find out there is one.
152
+ A caret range installs every later minor and patch of its major — `^1.2.0` takes `1.3.0` — and never a new major. A bot is how you hear about either, with its notes.
152
153
 
153
154
  ## Documentation
154
155