@intellectif/lk-core 1.7.0 → 1.9.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.
- package/CHANGELOG.md +33 -0
- package/dist/ai-check.cjs +77 -3
- package/dist/ai-check.cjs.map +1 -1
- package/dist/ai-check.d.cts +11 -3
- package/dist/ai-check.d.cts.map +1 -1
- package/dist/ai-check.d.ts +11 -3
- package/dist/ai-check.d.ts.map +1 -1
- package/dist/ai-check.js +77 -3
- package/dist/ai-check.js.map +1 -1
- package/dist/{ai-writing-B7oMCt66.js → ai-writing-DQjI9EFN.js} +2514 -136
- package/dist/ai-writing-DQjI9EFN.js.map +1 -0
- package/dist/{ai-writing-DrPTV3R2.cjs → ai-writing-DbpZpGRk.cjs} +2614 -122
- package/dist/ai-writing-DbpZpGRk.cjs.map +1 -0
- package/dist/{ai-B1wYrqcB.d.ts → ai-zhc9yhRj.d.cts} +454 -2
- package/dist/ai-zhc9yhRj.d.cts.map +1 -0
- package/dist/{ai-B1wYrqcB.d.cts → ai-zhc9yhRj.d.ts} +454 -2
- package/dist/ai-zhc9yhRj.d.ts.map +1 -0
- package/dist/{index-XCCoPoTU.d.cts → index-BeC8tAWf.d.cts} +2 -2
- package/dist/{index-XCCoPoTU.d.cts.map → index-BeC8tAWf.d.cts.map} +1 -1
- package/dist/{index-BU99GFTl.d.ts → index-Byar5VVs.d.ts} +2 -2
- package/dist/{index-BU99GFTl.d.ts.map → index-Byar5VVs.d.ts.map} +1 -1
- package/dist/{index-DP9rvyOz.d.cts → index-Ccj8oL_E.d.cts} +2 -2
- package/dist/{index-DP9rvyOz.d.cts.map → index-Ccj8oL_E.d.cts.map} +1 -1
- package/dist/{index-BTkMQtws.d.ts → index-CxkqS62X.d.ts} +89 -7
- package/dist/index-CxkqS62X.d.ts.map +1 -0
- package/dist/{index-BM8LeDWn.d.cts → index-DLsUnGHt.d.cts} +89 -7
- package/dist/index-DLsUnGHt.d.cts.map +1 -0
- package/dist/{index-BdXs4-en.d.ts → index-f4YuMgFb.d.ts} +2 -2
- package/dist/{index-BdXs4-en.d.ts.map → index-f4YuMgFb.d.ts.map} +1 -1
- package/dist/index.cjs +282 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +262 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +262 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +269 -7
- package/dist/index.js.map +1 -1
- package/dist/{item-group-CeDk7mfM.js → item-group-CKZk3txt.js} +2 -2
- package/dist/{item-group-CeDk7mfM.js.map → item-group-CKZk3txt.js.map} +1 -1
- package/dist/{item-group-8P3WFuUK.cjs → item-group-COP5OwEC.cjs} +2 -2
- package/dist/{item-group-8P3WFuUK.cjs.map → item-group-COP5OwEC.cjs.map} +1 -1
- package/dist/{registry-D92hz9iA.js → registry-Bw9grsCN.js} +339 -12
- package/dist/registry-Bw9grsCN.js.map +1 -0
- package/dist/{registry-hzrkTeIT.cjs → registry-C9O9txy5.cjs} +368 -11
- package/dist/registry-C9O9txy5.cjs.map +1 -0
- package/dist/{schemas-C7TViWCg.js → schemas-BJe3W6Xb.js} +3 -3
- package/dist/{schemas-C7TViWCg.js.map → schemas-BJe3W6Xb.js.map} +1 -1
- package/dist/{schemas-BWeskONy.cjs → schemas-CXlemRvB.cjs} +3 -3
- package/dist/{schemas-BWeskONy.cjs.map → schemas-CXlemRvB.cjs.map} +1 -1
- package/dist/schemas.cjs +3 -3
- package/dist/schemas.d.cts +1 -1
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +3 -3
- package/dist/{scoring-DD1GHcLI.js → scoring-BGKdff2i.js} +214 -26
- package/dist/scoring-BGKdff2i.js.map +1 -0
- package/dist/{scoring-CtkCFyFT.cjs → scoring-Db1CZeAn.cjs} +219 -25
- package/dist/scoring-Db1CZeAn.cjs.map +1 -0
- package/dist/scoring.cjs +3 -2
- package/dist/scoring.d.cts +3 -3
- package/dist/scoring.d.ts +3 -3
- package/dist/scoring.js +3 -3
- package/dist/{xapi-Cgicg-zU.js → xapi-BtBm8AWZ.js} +2 -2
- package/dist/{xapi-Cgicg-zU.js.map → xapi-BtBm8AWZ.js.map} +1 -1
- package/dist/{xapi-7btSpx6v.cjs → xapi-DOAqH9__.cjs} +2 -2
- package/dist/{xapi-7btSpx6v.cjs.map → xapi-DOAqH9__.cjs.map} +1 -1
- package/dist/xapi.cjs +1 -1
- package/dist/xapi.d.cts +1 -1
- package/dist/xapi.d.ts +1 -1
- package/dist/xapi.js +1 -1
- package/package.json +2 -2
- package/vectors/README.md +23 -0
- package/vectors/scoring.json +11967 -1
- package/vectors/validation.json +1298 -1
- package/vectors/variants.d.mts +20 -0
- package/vectors/variants.json +5753 -0
- package/vectors/variants.mjs +67 -0
- package/dist/ai-B1wYrqcB.d.cts.map +0 -1
- package/dist/ai-B1wYrqcB.d.ts.map +0 -1
- package/dist/ai-writing-B7oMCt66.js.map +0 -1
- package/dist/ai-writing-DrPTV3R2.cjs.map +0 -1
- package/dist/index-BM8LeDWn.d.cts.map +0 -1
- package/dist/index-BTkMQtws.d.ts.map +0 -1
- package/dist/registry-D92hz9iA.js.map +0 -1
- package/dist/registry-hzrkTeIT.cjs.map +0 -1
- package/dist/scoring-CtkCFyFT.cjs.map +0 -1
- package/dist/scoring-DD1GHcLI.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_registry = require("./registry-
|
|
3
|
-
const require_ai_writing = require("./ai-writing-
|
|
4
|
-
const require_scoring = require("./scoring-
|
|
5
|
-
const require_item_group = require("./item-group-
|
|
6
|
-
const require_schemas = require("./schemas-
|
|
7
|
-
const require_xapi = require("./xapi-
|
|
2
|
+
const require_registry = require("./registry-C9O9txy5.cjs");
|
|
3
|
+
const require_ai_writing = require("./ai-writing-DbpZpGRk.cjs");
|
|
4
|
+
const require_scoring = require("./scoring-Db1CZeAn.cjs");
|
|
5
|
+
const require_item_group = require("./item-group-COP5OwEC.cjs");
|
|
6
|
+
const require_schemas = require("./schemas-CXlemRvB.cjs");
|
|
7
|
+
const require_xapi = require("./xapi-DOAqH9__.cjs");
|
|
8
8
|
// src/delivery.ts
|
|
9
9
|
/**
|
|
10
10
|
* The policy that restricts nothing: every setting `true`. It is what an absent
|
|
@@ -1093,6 +1093,268 @@ function composeTimelineScore(entryKey, items, policy) {
|
|
|
1093
1093
|
items: own
|
|
1094
1094
|
}], policy);
|
|
1095
1095
|
}
|
|
1096
|
+
// src/versions.ts
|
|
1097
|
+
/**
|
|
1098
|
+
* Every code `critiqueVersions` reports, and its severity: a contract, as the
|
|
1099
|
+
* critic's codes are. `versions_shared_media` is `advice` for a picture both
|
|
1100
|
+
* forms may show, and a `warning` otherwise.
|
|
1101
|
+
*/
|
|
1102
|
+
const VERSION_FINDING_SEVERITY = {
|
|
1103
|
+
versions_section_mismatch: "invalid",
|
|
1104
|
+
versions_entry_count: "invalid",
|
|
1105
|
+
versions_type_mismatch: "invalid",
|
|
1106
|
+
versions_structure_mismatch: "invalid",
|
|
1107
|
+
versions_objectives_mismatch: "warning",
|
|
1108
|
+
versions_length_out_of_band: "warning",
|
|
1109
|
+
versions_near_copy: "warning",
|
|
1110
|
+
versions_same_key: "warning",
|
|
1111
|
+
versions_shared_media: "warning"
|
|
1112
|
+
};
|
|
1113
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1114
|
+
const listOf = (value) => Array.isArray(value) ? value : [];
|
|
1115
|
+
const stringOf = (value) => typeof value === "string" ? value : "";
|
|
1116
|
+
const key = (path) => path.join(".");
|
|
1117
|
+
function report(code, message, a, b, severity = VERSION_FINDING_SEVERITY[code]) {
|
|
1118
|
+
return {
|
|
1119
|
+
path: [...b ?? a ?? []],
|
|
1120
|
+
message,
|
|
1121
|
+
code,
|
|
1122
|
+
severity,
|
|
1123
|
+
...a !== void 0 ? { a: [...a] } : {},
|
|
1124
|
+
...b !== void 0 ? { b: [...b] } : {}
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function entriesOf(paper) {
|
|
1128
|
+
return listOf(paper?.sections).flatMap((section, s) => listOf(isRecord(section) ? section.entries : void 0).flatMap((value, index) => isRecord(value) ? [{
|
|
1129
|
+
path: [
|
|
1130
|
+
"sections",
|
|
1131
|
+
String(s),
|
|
1132
|
+
"entries",
|
|
1133
|
+
String(index)
|
|
1134
|
+
],
|
|
1135
|
+
section: s,
|
|
1136
|
+
index,
|
|
1137
|
+
value
|
|
1138
|
+
}] : []));
|
|
1139
|
+
}
|
|
1140
|
+
/** A group's items, or the entry itself: the slots a learner answers. */
|
|
1141
|
+
const itemsOf = (entry) => entry.value.type === "item-group" ? listOf(entry.value.items).flatMap((item, at) => isRecord(item) ? [{
|
|
1142
|
+
path: [
|
|
1143
|
+
...entry.path,
|
|
1144
|
+
"items",
|
|
1145
|
+
String(at)
|
|
1146
|
+
],
|
|
1147
|
+
value: item
|
|
1148
|
+
}] : []) : [{
|
|
1149
|
+
path: entry.path,
|
|
1150
|
+
value: entry.value
|
|
1151
|
+
}];
|
|
1152
|
+
const typeName = (value) => stringOf(value.type) || "no type";
|
|
1153
|
+
function pairEntries(aEntries, bEntries, given) {
|
|
1154
|
+
const pairs = [];
|
|
1155
|
+
const takenA = /* @__PURE__ */ new Set();
|
|
1156
|
+
const takenB = /* @__PURE__ */ new Set();
|
|
1157
|
+
const add = (a, b, by) => {
|
|
1158
|
+
pairs.push({
|
|
1159
|
+
a,
|
|
1160
|
+
b,
|
|
1161
|
+
by
|
|
1162
|
+
});
|
|
1163
|
+
takenA.add(key(a.path));
|
|
1164
|
+
takenB.add(key(b.path));
|
|
1165
|
+
};
|
|
1166
|
+
const aByPath = new Map(aEntries.map((one) => [key(one.path), one]));
|
|
1167
|
+
const bByPath = new Map(bEntries.map((one) => [key(one.path), one]));
|
|
1168
|
+
for (const pair of given ?? []) {
|
|
1169
|
+
const a = aByPath.get(key(pair.a.map(String)));
|
|
1170
|
+
const b = bByPath.get(key(pair.b.map(String)));
|
|
1171
|
+
if (a !== void 0 && b !== void 0 && !takenA.has(key(a.path)) && !takenB.has(key(b.path))) add(a, b, "pairs");
|
|
1172
|
+
}
|
|
1173
|
+
for (const a of aEntries) {
|
|
1174
|
+
const slotKey = a.value.slotKey;
|
|
1175
|
+
if (takenA.has(key(a.path)) || typeof slotKey !== "string") continue;
|
|
1176
|
+
const b = bEntries.find((one) => one.value.slotKey === slotKey && !takenB.has(key(one.path)));
|
|
1177
|
+
if (b !== void 0) add(a, b, "slotKey");
|
|
1178
|
+
}
|
|
1179
|
+
for (const a of aEntries) {
|
|
1180
|
+
if (takenA.has(key(a.path))) continue;
|
|
1181
|
+
const b = bEntries.find((one) => one.section === a.section && one.index === a.index && !takenB.has(key(one.path)));
|
|
1182
|
+
if (b !== void 0) add(a, b, "position");
|
|
1183
|
+
}
|
|
1184
|
+
return pairs;
|
|
1185
|
+
}
|
|
1186
|
+
/** A paired group's items, by their own `slotKey` when both have one, else by position. */
|
|
1187
|
+
function pairItems(pair) {
|
|
1188
|
+
const aItems = itemsOf(pair.a);
|
|
1189
|
+
const bItems = itemsOf(pair.b);
|
|
1190
|
+
if (pair.a.value.type !== "item-group" || pair.b.value.type !== "item-group") {
|
|
1191
|
+
const one = aItems[0];
|
|
1192
|
+
const two = bItems[0];
|
|
1193
|
+
return one !== void 0 && two !== void 0 ? [{
|
|
1194
|
+
a: one,
|
|
1195
|
+
b: two,
|
|
1196
|
+
by: pair.by
|
|
1197
|
+
}] : [];
|
|
1198
|
+
}
|
|
1199
|
+
const taken = /* @__PURE__ */ new Set();
|
|
1200
|
+
const pairs = [];
|
|
1201
|
+
aItems.forEach((a) => {
|
|
1202
|
+
const slotKey = a.value.slotKey;
|
|
1203
|
+
const found = typeof slotKey === "string" ? bItems.findIndex((b, index) => b.value.slotKey === slotKey && !taken.has(index)) : -1;
|
|
1204
|
+
if (found !== -1) {
|
|
1205
|
+
taken.add(found);
|
|
1206
|
+
pairs.push({
|
|
1207
|
+
a,
|
|
1208
|
+
b: bItems[found],
|
|
1209
|
+
by: "slotKey"
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
});
|
|
1213
|
+
aItems.forEach((a, at) => {
|
|
1214
|
+
if (pairs.some((one) => one.a === a) || at >= bItems.length || taken.has(at)) return;
|
|
1215
|
+
taken.add(at);
|
|
1216
|
+
pairs.push({
|
|
1217
|
+
a,
|
|
1218
|
+
b: bItems[at],
|
|
1219
|
+
by: "position"
|
|
1220
|
+
});
|
|
1221
|
+
});
|
|
1222
|
+
return pairs.sort((x, y) => aItems.indexOf(x.a) - aItems.indexOf(y.a));
|
|
1223
|
+
}
|
|
1224
|
+
const objectives = (value) => [...listOf(value.learningObjectives).filter((one) => typeof one === "string")].sort().join("\n");
|
|
1225
|
+
/**
|
|
1226
|
+
* Compares two forms of an exam slot by slot, and the whole of one with the
|
|
1227
|
+
* whole of the other: whether they are parallel — the same blueprint, types,
|
|
1228
|
+
* structure and scoring (`invalid` when not) — and whether a learner who sat
|
|
1229
|
+
* one would meet the other again: a near copy anywhere in the other form, a
|
|
1230
|
+
* shared right answer in a paired slot, the same recording (`warning`), or
|
|
1231
|
+
* the same picture (`advice` while `allowSharedImages`, its default).
|
|
1232
|
+
* Objectives and lengths that differ are warnings.
|
|
1233
|
+
*
|
|
1234
|
+
* Slots are paired by `pairs` (paths from each paper's root, as
|
|
1235
|
+
* `generateVariants`' pairs give them once a host places them), then by
|
|
1236
|
+
* `slotKey`, then by position: the same entry of the same section. A paired
|
|
1237
|
+
* group's items pair by their own `slotKey`, then by position.
|
|
1238
|
+
*
|
|
1239
|
+
* It reads content as stored, finished or not, and never throws.
|
|
1240
|
+
*/
|
|
1241
|
+
function critiqueVersions(a, b, options = {}) {
|
|
1242
|
+
const findings = [];
|
|
1243
|
+
const aSections = listOf(a?.sections);
|
|
1244
|
+
const bSections = listOf(b?.sections);
|
|
1245
|
+
if (aSections.length !== bSections.length) findings.push(report("versions_section_mismatch", `The second form has ${bSections.length} sections; the first has ${aSections.length}.`, void 0, void 0));
|
|
1246
|
+
for (let s = 0; s < Math.min(aSections.length, bSections.length); s += 1) {
|
|
1247
|
+
const one = isRecord(aSections[s]) ? aSections[s] : {};
|
|
1248
|
+
const two = isRecord(bSections[s]) ? bSections[s] : {};
|
|
1249
|
+
const at = ["sections", String(s)];
|
|
1250
|
+
if (one.key !== two.key || one.title !== two.title) findings.push(report("versions_section_mismatch", `Section ${s + 1} is "${stringOf(two.title) || stringOf(two.key)}" in the second form and "${stringOf(one.title) || stringOf(one.key)}" in the first.`, at, at));
|
|
1251
|
+
const aCount = listOf(one.entries).length;
|
|
1252
|
+
const bCount = listOf(two.entries).length;
|
|
1253
|
+
if (aCount !== bCount) findings.push(report("versions_entry_count", `Section ${s + 1} has ${bCount} entries in the second form and ${aCount} in the first.`, [...at, "entries"], [...at, "entries"]));
|
|
1254
|
+
}
|
|
1255
|
+
const aEntries = entriesOf(a);
|
|
1256
|
+
const bEntries = entriesOf(b);
|
|
1257
|
+
const pairs = pairEntries(aEntries, bEntries, options.pairs);
|
|
1258
|
+
let structureMismatches = 0;
|
|
1259
|
+
let paired = 0;
|
|
1260
|
+
const slots = [];
|
|
1261
|
+
for (const pair of pairs) {
|
|
1262
|
+
slots.push({
|
|
1263
|
+
a: pair.a.path,
|
|
1264
|
+
b: pair.b.path,
|
|
1265
|
+
by: pair.by
|
|
1266
|
+
});
|
|
1267
|
+
if (pair.a.value.type !== pair.b.value.type) {
|
|
1268
|
+
structureMismatches += 1;
|
|
1269
|
+
findings.push(report("versions_type_mismatch", `The second form has ${typeName(pair.b.value)} here; the first has ${typeName(pair.a.value)}.`, pair.a.path, pair.b.path));
|
|
1270
|
+
continue;
|
|
1271
|
+
}
|
|
1272
|
+
const misses = require_ai_writing.structureMisses(pair.a.value, pair.b.value);
|
|
1273
|
+
if (misses.length > 0) structureMismatches += 1;
|
|
1274
|
+
for (const miss of misses) {
|
|
1275
|
+
const code = miss.path[miss.path.length - 1] === "type" ? "versions_type_mismatch" : miss.path.length === 1 && miss.path[0] === "items" ? "versions_entry_count" : "versions_structure_mismatch";
|
|
1276
|
+
findings.push(report(code, miss.message, [...pair.a.path, ...miss.path], [...pair.b.path, ...miss.path]));
|
|
1277
|
+
}
|
|
1278
|
+
for (const miss of require_ai_writing.lengthMisses(pair.a.value, pair.b.value, options.lengthTolerance)) findings.push(report("versions_length_out_of_band", `${miss.words} words; the first form's has ${miss.exemplarWords}, so ${miss.bounds[0]} to ${miss.bounds[1]}.`, [...pair.a.path, ...miss.path], [...pair.b.path, ...miss.path]));
|
|
1279
|
+
const items = pairItems(pair);
|
|
1280
|
+
if (pair.a.value.type === "item-group") for (const item of items) slots.push({
|
|
1281
|
+
a: item.a.path,
|
|
1282
|
+
b: item.b.path,
|
|
1283
|
+
by: item.by
|
|
1284
|
+
});
|
|
1285
|
+
for (const item of items) {
|
|
1286
|
+
if (item.a.value.type !== item.b.value.type) continue;
|
|
1287
|
+
paired += 1;
|
|
1288
|
+
if ((item.a.value.learningObjectives !== void 0 || item.b.value.learningObjectives !== void 0) && objectives(item.a.value) !== objectives(item.b.value)) findings.push(report("versions_objectives_mismatch", "The two forms test different learning objectives here.", item.a.path, item.b.path));
|
|
1289
|
+
const aKeys = require_ai_writing.keysOf(item.a.value);
|
|
1290
|
+
for (const slot of require_ai_writing.keysOf(item.b.value)) {
|
|
1291
|
+
const match = aKeys.find((one) => one.slot === slot.slot);
|
|
1292
|
+
const shared = match !== void 0 ? require_ai_writing.sharedAnswers(slot, match) : [];
|
|
1293
|
+
if (shared.length > 0) findings.push(report("versions_same_key", `The right answer "${shared[0]}" is the same in both forms: a learner who sat the first scores again by memory.`, [...item.a.path, ...match.path], [...item.b.path, ...slot.path]));
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
const pairedA = new Set(slots.flatMap((slot) => slot.a !== null ? [key(slot.a)] : []));
|
|
1298
|
+
const pairedB = new Set(slots.flatMap((slot) => slot.b !== null ? [key(slot.b)] : []));
|
|
1299
|
+
for (const entry of aEntries) for (const one of entry.value.type === "item-group" ? [{ path: entry.path }, ...itemsOf(entry)] : [entry]) if (!pairedA.has(key(one.path))) slots.push({
|
|
1300
|
+
a: one.path,
|
|
1301
|
+
b: null,
|
|
1302
|
+
by: "position"
|
|
1303
|
+
});
|
|
1304
|
+
for (const entry of bEntries) for (const one of entry.value.type === "item-group" ? [{ path: entry.path }, ...itemsOf(entry)] : [entry]) if (!pairedB.has(key(one.path))) slots.push({
|
|
1305
|
+
a: null,
|
|
1306
|
+
b: one.path,
|
|
1307
|
+
by: "position"
|
|
1308
|
+
});
|
|
1309
|
+
const aTexts = aEntries.flatMap((entry) => require_ai_writing.textsOf(entry.value).map((text) => ({
|
|
1310
|
+
...text,
|
|
1311
|
+
path: [...entry.path, ...text.path]
|
|
1312
|
+
})));
|
|
1313
|
+
for (const entry of bEntries) for (const text of require_ai_writing.textsOf(entry.value)) {
|
|
1314
|
+
let best;
|
|
1315
|
+
for (const other of aTexts) {
|
|
1316
|
+
if (other.kind !== text.kind) continue;
|
|
1317
|
+
const score = require_ai_writing.textSimilarity(other.text, text.text);
|
|
1318
|
+
if (score >= .5 && (best === void 0 || score > best.score)) best = {
|
|
1319
|
+
score,
|
|
1320
|
+
path: other.path
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
if (best !== void 0) findings.push(report("versions_near_copy", `This reads like the first form's text here (similarity ${require_ai_writing.shownScore(best.score)}).`, best.path, [...entry.path, ...text.path]));
|
|
1324
|
+
}
|
|
1325
|
+
const aOptions = aEntries.flatMap((entry) => itemsOf(entry).flatMap((item) => {
|
|
1326
|
+
const set = require_ai_writing.optionSet(item.value);
|
|
1327
|
+
return set !== null ? [{
|
|
1328
|
+
path: item.path,
|
|
1329
|
+
set: set.join("\n")
|
|
1330
|
+
}] : [];
|
|
1331
|
+
}));
|
|
1332
|
+
for (const entry of bEntries) for (const item of itemsOf(entry)) {
|
|
1333
|
+
const set = require_ai_writing.optionSet(item.value);
|
|
1334
|
+
const match = set !== null ? aOptions.find((other) => other.set === set.join("\n")) : void 0;
|
|
1335
|
+
if (match !== void 0) findings.push(report("versions_near_copy", "These options are the first form's, in another order.", [...match.path, "options"], [...item.path, "options"]));
|
|
1336
|
+
}
|
|
1337
|
+
const allowImages = options.allowSharedImages !== false;
|
|
1338
|
+
const aFiles = /* @__PURE__ */ new Map();
|
|
1339
|
+
for (const entry of aEntries) for (const ref of require_ai_writing.listMediaRefs(entry.value)) if (ref.url !== null && ref.url !== "" && !aFiles.has(ref.url)) aFiles.set(ref.url, [...entry.path, ...ref.path.map(String)]);
|
|
1340
|
+
for (const entry of bEntries) for (const ref of require_ai_writing.listMediaRefs(entry.value)) {
|
|
1341
|
+
const first = ref.url !== null ? aFiles.get(ref.url) : void 0;
|
|
1342
|
+
if (first === void 0) continue;
|
|
1343
|
+
const picture = ref.kind === "image";
|
|
1344
|
+
findings.push(report("versions_shared_media", picture ? "Both forms show this picture." : "Both forms use this file: a learner who sat the first hears or sees it again.", first, [...entry.path, ...ref.path.map(String)], picture && allowImages ? "advice" : "warning"));
|
|
1345
|
+
}
|
|
1346
|
+
const count = (entries) => entries.reduce((sum, entry) => sum + itemsOf(entry).length, 0);
|
|
1347
|
+
return {
|
|
1348
|
+
findings,
|
|
1349
|
+
slots,
|
|
1350
|
+
summary: {
|
|
1351
|
+
aItems: count(aEntries),
|
|
1352
|
+
bItems: count(bEntries),
|
|
1353
|
+
paired,
|
|
1354
|
+
structureMismatches
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1096
1358
|
exports.AI_COACHING_MAX_TIP_LENGTH = require_ai_writing.AI_COACHING_MAX_TIP_LENGTH;
|
|
1097
1359
|
exports.AI_COACHING_MAX_WORDS = require_ai_writing.AI_COACHING_MAX_WORDS;
|
|
1098
1360
|
exports.AI_CRITIQUE_MAX_FIELD_LENGTH = require_ai_writing.AI_CRITIQUE_MAX_FIELD_LENGTH;
|
|
@@ -1104,6 +1366,12 @@ exports.AI_GRADING_PROBABILITY_TOLERANCE = require_ai_writing.AI_GRADING_PROBABI
|
|
|
1104
1366
|
exports.AI_HINT_TYPES = require_ai_writing.AI_HINT_TYPES;
|
|
1105
1367
|
exports.AI_MATERIAL_MAX_LENGTH = require_ai_writing.AI_MATERIAL_MAX_LENGTH;
|
|
1106
1368
|
exports.AI_TEXT_MAX_LENGTH = require_ai_writing.AI_TEXT_MAX_LENGTH;
|
|
1369
|
+
exports.AI_VARIANTS_MAX_EXEMPLARS = require_ai_writing.AI_VARIANTS_MAX_EXEMPLARS;
|
|
1370
|
+
exports.AI_VARIANTS_MAX_MATERIAL_LENGTH = require_ai_writing.AI_VARIANTS_MAX_MATERIAL_LENGTH;
|
|
1371
|
+
exports.AI_VARIANTS_MAX_REPAIRS = require_ai_writing.AI_VARIANTS_MAX_REPAIRS;
|
|
1372
|
+
exports.AI_VARIANT_CODE_SEVERITY = require_ai_writing.AI_VARIANT_CODE_SEVERITY;
|
|
1373
|
+
exports.AI_VARIANT_LENGTH_BANDS = require_ai_writing.AI_VARIANT_LENGTH_BANDS;
|
|
1374
|
+
exports.AI_VARIANT_NEAR_COPY_THRESHOLD = require_ai_writing.AI_VARIANT_NEAR_COPY_THRESHOLD;
|
|
1107
1375
|
exports.AI_WRITING_MAX_CORRECTIONS = require_ai_writing.AI_WRITING_MAX_CORRECTIONS;
|
|
1108
1376
|
exports.AI_WRITING_MAX_FIELD_LENGTH = require_ai_writing.AI_WRITING_MAX_FIELD_LENGTH;
|
|
1109
1377
|
exports.ActivitySchemaError = require_registry.ActivitySchemaError;
|
|
@@ -1131,6 +1399,7 @@ exports.TIMELINE_MAX_ITEMS = require_item_group.TIMELINE_MAX_ITEMS;
|
|
|
1131
1399
|
exports.TIMELINE_MAX_QUIZZES = require_item_group.TIMELINE_MAX_QUIZZES;
|
|
1132
1400
|
exports.TIMELINE_MAX_TITLE_LENGTH = require_item_group.TIMELINE_MAX_TITLE_LENGTH;
|
|
1133
1401
|
exports.UnknownActivityTypeError = require_registry.UnknownActivityTypeError;
|
|
1402
|
+
exports.VERSION_FINDING_SEVERITY = VERSION_FINDING_SEVERITY;
|
|
1134
1403
|
exports.XAPIVerb = require_xapi.XAPIVerb;
|
|
1135
1404
|
exports.XAPI_VERB_DISPLAY = require_xapi.XAPI_VERB_DISPLAY;
|
|
1136
1405
|
exports.aiAllowedByContent = require_ai_writing.aiAllowedByContent;
|
|
@@ -1142,7 +1411,10 @@ exports.aiExplanationRequest = require_ai_writing.aiExplanationRequest;
|
|
|
1142
1411
|
exports.aiGradeOf = require_ai_writing.aiGradeOf;
|
|
1143
1412
|
exports.aiGradingRequest = require_ai_writing.aiGradingRequest;
|
|
1144
1413
|
exports.aiHintRequest = require_ai_writing.aiHintRequest;
|
|
1414
|
+
exports.aiSpeakingGradingRequest = require_ai_writing.aiSpeakingGradingRequest;
|
|
1145
1415
|
exports.aiSupports = require_ai_writing.aiSupports;
|
|
1416
|
+
exports.aiVariantsRepairRequest = require_ai_writing.aiVariantsRepairRequest;
|
|
1417
|
+
exports.aiVariantsRequest = require_ai_writing.aiVariantsRequest;
|
|
1146
1418
|
exports.aiWritingFeedbackRequest = require_ai_writing.aiWritingFeedbackRequest;
|
|
1147
1419
|
exports.alignDictation = require_registry.alignDictation;
|
|
1148
1420
|
exports.alignReadAloud = require_scoring.alignReadAloud;
|
|
@@ -1157,6 +1429,7 @@ exports.checkAiDrafts = require_ai_writing.checkAiDrafts;
|
|
|
1157
1429
|
exports.checkAiExplanation = require_ai_writing.checkAiExplanation;
|
|
1158
1430
|
exports.checkAiGrading = require_ai_writing.checkAiGrading;
|
|
1159
1431
|
exports.checkAiHint = require_ai_writing.checkAiHint;
|
|
1432
|
+
exports.checkAiVariants = require_ai_writing.checkAiVariants;
|
|
1160
1433
|
exports.checkAiWritingFeedback = require_ai_writing.checkAiWritingFeedback;
|
|
1161
1434
|
exports.classifyBand = require_scoring.classifyBand;
|
|
1162
1435
|
exports.combineDeliveryPolicies = combineDeliveryPolicies;
|
|
@@ -1172,6 +1445,7 @@ exports.createItemGroupDraft = require_ai_writing.createItemGroupDraft;
|
|
|
1172
1445
|
exports.critiqueDraft = require_ai_writing.critiqueDraft;
|
|
1173
1446
|
exports.critiqueDrafts = require_ai_writing.critiqueDrafts;
|
|
1174
1447
|
exports.critiqueItemGroupDraft = require_ai_writing.critiqueItemGroupDraft;
|
|
1448
|
+
exports.critiqueVersions = critiqueVersions;
|
|
1175
1449
|
exports.defineActivityType = require_registry.defineActivityType;
|
|
1176
1450
|
exports.dictationJsonSchema = require_schemas.dictationJsonSchema;
|
|
1177
1451
|
exports.dictationReferenceWords = require_registry.dictationReferenceWords;
|
|
@@ -1188,10 +1462,12 @@ exports.flattenSequence = flattenSequence;
|
|
|
1188
1462
|
exports.gapSelectJsonSchema = require_schemas.gapSelectJsonSchema;
|
|
1189
1463
|
exports.gapSelectType = require_registry.gapSelectType;
|
|
1190
1464
|
exports.generateDrafts = require_ai_writing.generateDrafts;
|
|
1465
|
+
exports.generateVariants = require_ai_writing.generateVariants;
|
|
1191
1466
|
exports.getActivityTypeDescriptor = require_registry.getActivityTypeDescriptor;
|
|
1192
1467
|
exports.gradeFromJudgement = require_scoring.gradeFromJudgement;
|
|
1193
1468
|
exports.gradeFromRubric = require_scoring.gradeFromRubric;
|
|
1194
1469
|
exports.gradeReadAloud = require_scoring.gradeReadAloud;
|
|
1470
|
+
exports.gradeSpeakingResponse = require_scoring.gradeSpeakingResponse;
|
|
1195
1471
|
exports.graderConfiguration = require_scoring.graderConfiguration;
|
|
1196
1472
|
exports.gte = require_scoring.gte;
|
|
1197
1473
|
exports.hasGrade = require_scoring.hasGrade;
|