@playcademy/sandbox 0.10.1-beta.1 → 0.10.1-beta.3
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/dist/cli.js +72 -14
- package/dist/server.js +72 -14
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1128,7 +1128,7 @@ var package_default;
|
|
|
1128
1128
|
var init_package = __esm(() => {
|
|
1129
1129
|
package_default = {
|
|
1130
1130
|
name: "@playcademy/sandbox",
|
|
1131
|
-
version: "0.10.1-beta.
|
|
1131
|
+
version: "0.10.1-beta.3",
|
|
1132
1132
|
description: "Local development server for Playcademy game development",
|
|
1133
1133
|
type: "module",
|
|
1134
1134
|
exports: {
|
|
@@ -11002,6 +11002,35 @@ function scorePlatformAssessmentItem(item, responses) {
|
|
|
11002
11002
|
isCorrect: verdicts.length > 0 && verdicts.every(Boolean)
|
|
11003
11003
|
};
|
|
11004
11004
|
}
|
|
11005
|
+
function reviewStandardRef({
|
|
11006
|
+
framework,
|
|
11007
|
+
identifier
|
|
11008
|
+
}) {
|
|
11009
|
+
return { framework, identifier };
|
|
11010
|
+
}
|
|
11011
|
+
function reportReviewRequiredPairUnavailable(review, administeredItemIdentifiers2, report) {
|
|
11012
|
+
const administered = new Set(administeredItemIdentifiers2);
|
|
11013
|
+
const failures = [];
|
|
11014
|
+
for (const standard of review.standards.filter((entry) => entry.requireBothQuestions)) {
|
|
11015
|
+
const key = assessmentStandardRefKey(standard);
|
|
11016
|
+
const selected = new Set(review.selections.filter((selection) => assessmentStandardRefKey(selection.standard) === key).map((selection) => selection.itemIdentifier));
|
|
11017
|
+
const administeredCount = [...selected].filter((identifier) => administered.has(identifier)).length;
|
|
11018
|
+
if (selected.size < 2 || administeredCount === 1) {
|
|
11019
|
+
failures.push({
|
|
11020
|
+
standard: reviewStandardRef(standard),
|
|
11021
|
+
reason: selected.size < 2 ? "selection_shortage" : "not_administered",
|
|
11022
|
+
requiredCount: 2,
|
|
11023
|
+
selectedCount: selected.size,
|
|
11024
|
+
administeredCount
|
|
11025
|
+
});
|
|
11026
|
+
}
|
|
11027
|
+
}
|
|
11028
|
+
if (failures.length > 0) {
|
|
11029
|
+
try {
|
|
11030
|
+
report({ code: "REVIEW_REQUIRED_PAIR_UNAVAILABLE", failures });
|
|
11031
|
+
} catch {}
|
|
11032
|
+
}
|
|
11033
|
+
}
|
|
11005
11034
|
function reviewStandardFieldsWithinLimits(input) {
|
|
11006
11035
|
return input.framework.trim().length <= TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standardFieldLength && input.identifier.trim().length <= TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standardFieldLength;
|
|
11007
11036
|
}
|
|
@@ -11031,6 +11060,9 @@ function canonicalRequestStandards(standards) {
|
|
|
11031
11060
|
}
|
|
11032
11061
|
const canonical = new Map;
|
|
11033
11062
|
for (const input of standards) {
|
|
11063
|
+
if (input.requireBothQuestions !== undefined && typeof input.requireBothQuestions !== "boolean") {
|
|
11064
|
+
throw new Error("review standard requireBothQuestions must be a boolean");
|
|
11065
|
+
}
|
|
11034
11066
|
const standard = canonicalAssessmentStandardRef(input);
|
|
11035
11067
|
if (!reviewStandardFieldsWithinLimits(standard)) {
|
|
11036
11068
|
throw new RangeError(`Review standard fields may contain at most ${TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standardFieldLength} characters`);
|
|
@@ -11039,13 +11071,19 @@ function canonicalRequestStandards(standards) {
|
|
|
11039
11071
|
throw new Error("Review standards require a framework and identifier");
|
|
11040
11072
|
}
|
|
11041
11073
|
const key = assessmentStandardRefKey(standard);
|
|
11042
|
-
if (!canonical.has(key)) {
|
|
11043
|
-
canonical.set(key,
|
|
11074
|
+
if (!canonical.has(key) || input.requireBothQuestions) {
|
|
11075
|
+
canonical.set(key, {
|
|
11076
|
+
...standard,
|
|
11077
|
+
...input.requireBothQuestions ? { requireBothQuestions: true } : {}
|
|
11078
|
+
});
|
|
11044
11079
|
}
|
|
11045
11080
|
}
|
|
11046
|
-
return [...canonical.values()]
|
|
11081
|
+
return [...canonical.values()];
|
|
11047
11082
|
}
|
|
11048
11083
|
function normalizeReviewRequest(request) {
|
|
11084
|
+
if ("requireBothQuestions" in request && request.requireBothQuestions !== undefined) {
|
|
11085
|
+
throw new Error("Set requireBothQuestions on individual review standards, not the review request");
|
|
11086
|
+
}
|
|
11049
11087
|
const candidateItemsPerStandard = request.candidateItemsPerStandard ?? 1;
|
|
11050
11088
|
if (!Number.isInteger(candidateItemsPerStandard) || candidateItemsPerStandard <= 0 || candidateItemsPerStandard > TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard) {
|
|
11051
11089
|
throw new RangeError(`candidateItemsPerStandard must be a positive integer at most ${TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard}`);
|
|
@@ -11054,17 +11092,22 @@ function normalizeReviewRequest(request) {
|
|
|
11054
11092
|
if (standards.length === 0) {
|
|
11055
11093
|
throw new Error("At least one review standard is required");
|
|
11056
11094
|
}
|
|
11057
|
-
return {
|
|
11095
|
+
return {
|
|
11096
|
+
standards,
|
|
11097
|
+
candidateItemsPerStandard
|
|
11098
|
+
};
|
|
11058
11099
|
}
|
|
11059
11100
|
function reviewRequestFingerprint(request, policy) {
|
|
11060
11101
|
const normalized = normalizeReviewRequest(request);
|
|
11102
|
+
const requiredStandardKeys = normalized.standards.filter((standard) => standard.requireBothQuestions).map(assessmentStandardRefKey);
|
|
11061
11103
|
return JSON.stringify({
|
|
11062
11104
|
kind: "standards-review",
|
|
11063
11105
|
policy: {
|
|
11064
11106
|
version: policy.version
|
|
11065
11107
|
},
|
|
11066
11108
|
candidateItemsPerStandard: normalized.candidateItemsPerStandard,
|
|
11067
|
-
standardKeys: normalized.standards.map(assessmentStandardRefKey)
|
|
11109
|
+
standardKeys: normalized.standards.map(assessmentStandardRefKey),
|
|
11110
|
+
...requiredStandardKeys.length > 0 ? { requiredStandardKeys } : {}
|
|
11068
11111
|
});
|
|
11069
11112
|
}
|
|
11070
11113
|
function reviewQuestionLineItemId(parentLineItemId, itemIdentifier) {
|
|
@@ -11290,9 +11333,10 @@ function rankedCandidatesByStandard(bank, exposures) {
|
|
|
11290
11333
|
return byStandard;
|
|
11291
11334
|
}
|
|
11292
11335
|
function reviewSlots(request) {
|
|
11293
|
-
return request.standards.flatMap((standard) => Array.from({ length: request.candidateItemsPerStandard }, () => ({
|
|
11294
|
-
standard,
|
|
11295
|
-
standardKey: assessmentStandardRefKey(standard)
|
|
11336
|
+
return request.standards.flatMap((standard, servingIndex) => Array.from({ length: request.candidateItemsPerStandard }, () => ({
|
|
11337
|
+
standard: reviewStandardRef(standard),
|
|
11338
|
+
standardKey: assessmentStandardRefKey(standard),
|
|
11339
|
+
servingIndex
|
|
11296
11340
|
})));
|
|
11297
11341
|
}
|
|
11298
11342
|
function matchingCandidates(candidatesByStandard, slotCount) {
|
|
@@ -11405,7 +11449,7 @@ function fulfillment(request, candidatesByStandard, selections) {
|
|
|
11405
11449
|
const selected = selectedByStandard.get(key) ?? 0;
|
|
11406
11450
|
return selected < request.candidateItemsPerStandard ? [
|
|
11407
11451
|
{
|
|
11408
|
-
standard,
|
|
11452
|
+
standard: reviewStandardRef(standard),
|
|
11409
11453
|
requested: request.candidateItemsPerStandard,
|
|
11410
11454
|
selected,
|
|
11411
11455
|
eligible: candidatesByStandard.get(key)?.length ?? 0
|
|
@@ -11430,10 +11474,10 @@ function fulfillment(request, candidatesByStandard, selections) {
|
|
|
11430
11474
|
function selectReviewItems(input) {
|
|
11431
11475
|
const request = normalizeReviewRequest(input.request);
|
|
11432
11476
|
const candidatesByStandard = rankedCandidatesByStandard(input.bank, input.exposures);
|
|
11433
|
-
const slots = reviewSlots(request);
|
|
11477
|
+
const slots = reviewSlots(request).toSorted((left, right) => compareCodeUnits(left.standardKey, right.standardKey));
|
|
11434
11478
|
const boundedCandidates = matchingCandidates(candidatesByStandard, slots.length);
|
|
11435
11479
|
const selected = preferredDistinctMatching(slots, boundedCandidates);
|
|
11436
|
-
const selections = [...selected.entries()].toSorted(([left], [right]) => left - right).map(([index, itemIdentifier]) => ({
|
|
11480
|
+
const selections = [...selected.entries()].toSorted(([left], [right]) => slots[left].servingIndex - slots[right].servingIndex || left - right).map(([index, itemIdentifier]) => ({
|
|
11437
11481
|
standard: slots[index].standard,
|
|
11438
11482
|
itemIdentifier
|
|
11439
11483
|
}));
|
|
@@ -11572,6 +11616,9 @@ function isAssessmentScore(value) {
|
|
|
11572
11616
|
function isAssessmentStandardRef(value) {
|
|
11573
11617
|
return isRecord(value) && typeof value.framework === "string" && value.framework.length > 0 && typeof value.identifier === "string" && value.identifier.length > 0;
|
|
11574
11618
|
}
|
|
11619
|
+
function isAssessmentReviewStandard(value) {
|
|
11620
|
+
return isRecord(value) && isAssessmentStandardRef(value) && (value.requireBothQuestions === undefined || typeof value.requireBothQuestions === "boolean");
|
|
11621
|
+
}
|
|
11575
11622
|
function isReviewFulfillment(value) {
|
|
11576
11623
|
if (!isRecord(value) || value.status !== "complete" && value.status !== "partial" || !Number.isInteger(value.requestedItemCount) || !Number.isInteger(value.selectedItemCount) || !Array.isArray(value.shortages)) {
|
|
11577
11624
|
return false;
|
|
@@ -11646,7 +11693,7 @@ function isRoutedDiagnosticAttemptMetadata(value, itemSubmissions, responseVersi
|
|
|
11646
11693
|
});
|
|
11647
11694
|
}
|
|
11648
11695
|
function isReviewAttemptMetadata(value) {
|
|
11649
|
-
return isRecord(value) && typeof value.requestFingerprint === "string" && typeof value.bankRevision === "string" && Array.isArray(value.standards) && value.standards.every(
|
|
11696
|
+
return isRecord(value) && typeof value.requestFingerprint === "string" && typeof value.bankRevision === "string" && Array.isArray(value.standards) && value.standards.every(isAssessmentReviewStandard) && Number.isInteger(value.candidateItemsPerStandard) && value.requireBothQuestions === undefined && Array.isArray(value.selections) && value.selections.every((selection) => isRecord(selection) && isAssessmentStandardRef(selection.standard) && typeof selection.itemIdentifier === "string") && isReviewFulfillment(value.fulfillment);
|
|
11650
11697
|
}
|
|
11651
11698
|
function isOptionalInteger(value) {
|
|
11652
11699
|
return value === undefined || Number.isInteger(value);
|
|
@@ -12344,7 +12391,8 @@ var init_assessment_runtime2 = __esm(() => {
|
|
|
12344
12391
|
}),
|
|
12345
12392
|
StartAssessmentBaseSchema.extend({
|
|
12346
12393
|
purpose: exports_external.literal("review"),
|
|
12347
|
-
|
|
12394
|
+
requireBothQuestions: exports_external.never().optional(),
|
|
12395
|
+
standards: exports_external.array(AssessmentStandardRefSchema2.and(exports_external.object({ requireBothQuestions: exports_external.boolean().optional() }))).min(1).max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standards),
|
|
12348
12396
|
candidateItemsPerStandard: exports_external.number().int().positive().max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard).optional()
|
|
12349
12397
|
}),
|
|
12350
12398
|
StartAssessmentBaseSchema.extend({
|
|
@@ -104518,6 +104566,16 @@ var init_timeback_assessment_runtime_service = __esm(async () => {
|
|
|
104518
104566
|
};
|
|
104519
104567
|
});
|
|
104520
104568
|
if (accepted.repair) {
|
|
104569
|
+
const { metadata: metadata2 } = accepted.repair.graded;
|
|
104570
|
+
if (metadata2.purpose === "review") {
|
|
104571
|
+
reportReviewRequiredPairUnavailable(metadata2.review, metadata2.itemSubmissions.map((item) => item.itemIdentifier), (error88) => addEvent("assessment.review_required_pair_unavailable", {
|
|
104572
|
+
"app.assessment.attempt_id": params.attemptId,
|
|
104573
|
+
"app.assessment.submission_id": input.submissionId,
|
|
104574
|
+
"app.error.code": error88.code,
|
|
104575
|
+
"app.assessment.review.required_pair_failure_count": error88.failures.length,
|
|
104576
|
+
"app.assessment.review.required_pair_failures": error88.failures.map((failure) => JSON.stringify(failure))
|
|
104577
|
+
}));
|
|
104578
|
+
}
|
|
104521
104579
|
this.reconcileTranscriptChildren(accepted.repair.context, accepted.repair.graded).catch((error88) => this.recordTranscriptFailure("completion_repair", params.attemptId, error88));
|
|
104522
104580
|
}
|
|
104523
104581
|
if (accepted.emission) {
|
package/dist/server.js
CHANGED
|
@@ -1127,7 +1127,7 @@ var package_default;
|
|
|
1127
1127
|
var init_package = __esm(() => {
|
|
1128
1128
|
package_default = {
|
|
1129
1129
|
name: "@playcademy/sandbox",
|
|
1130
|
-
version: "0.10.1-beta.
|
|
1130
|
+
version: "0.10.1-beta.3",
|
|
1131
1131
|
description: "Local development server for Playcademy game development",
|
|
1132
1132
|
type: "module",
|
|
1133
1133
|
exports: {
|
|
@@ -11001,6 +11001,35 @@ function scorePlatformAssessmentItem(item, responses) {
|
|
|
11001
11001
|
isCorrect: verdicts.length > 0 && verdicts.every(Boolean)
|
|
11002
11002
|
};
|
|
11003
11003
|
}
|
|
11004
|
+
function reviewStandardRef({
|
|
11005
|
+
framework,
|
|
11006
|
+
identifier
|
|
11007
|
+
}) {
|
|
11008
|
+
return { framework, identifier };
|
|
11009
|
+
}
|
|
11010
|
+
function reportReviewRequiredPairUnavailable(review, administeredItemIdentifiers2, report) {
|
|
11011
|
+
const administered = new Set(administeredItemIdentifiers2);
|
|
11012
|
+
const failures = [];
|
|
11013
|
+
for (const standard of review.standards.filter((entry) => entry.requireBothQuestions)) {
|
|
11014
|
+
const key = assessmentStandardRefKey(standard);
|
|
11015
|
+
const selected = new Set(review.selections.filter((selection) => assessmentStandardRefKey(selection.standard) === key).map((selection) => selection.itemIdentifier));
|
|
11016
|
+
const administeredCount = [...selected].filter((identifier) => administered.has(identifier)).length;
|
|
11017
|
+
if (selected.size < 2 || administeredCount === 1) {
|
|
11018
|
+
failures.push({
|
|
11019
|
+
standard: reviewStandardRef(standard),
|
|
11020
|
+
reason: selected.size < 2 ? "selection_shortage" : "not_administered",
|
|
11021
|
+
requiredCount: 2,
|
|
11022
|
+
selectedCount: selected.size,
|
|
11023
|
+
administeredCount
|
|
11024
|
+
});
|
|
11025
|
+
}
|
|
11026
|
+
}
|
|
11027
|
+
if (failures.length > 0) {
|
|
11028
|
+
try {
|
|
11029
|
+
report({ code: "REVIEW_REQUIRED_PAIR_UNAVAILABLE", failures });
|
|
11030
|
+
} catch {}
|
|
11031
|
+
}
|
|
11032
|
+
}
|
|
11004
11033
|
function reviewStandardFieldsWithinLimits(input) {
|
|
11005
11034
|
return input.framework.trim().length <= TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standardFieldLength && input.identifier.trim().length <= TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standardFieldLength;
|
|
11006
11035
|
}
|
|
@@ -11030,6 +11059,9 @@ function canonicalRequestStandards(standards) {
|
|
|
11030
11059
|
}
|
|
11031
11060
|
const canonical = new Map;
|
|
11032
11061
|
for (const input of standards) {
|
|
11062
|
+
if (input.requireBothQuestions !== undefined && typeof input.requireBothQuestions !== "boolean") {
|
|
11063
|
+
throw new Error("review standard requireBothQuestions must be a boolean");
|
|
11064
|
+
}
|
|
11033
11065
|
const standard = canonicalAssessmentStandardRef(input);
|
|
11034
11066
|
if (!reviewStandardFieldsWithinLimits(standard)) {
|
|
11035
11067
|
throw new RangeError(`Review standard fields may contain at most ${TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standardFieldLength} characters`);
|
|
@@ -11038,13 +11070,19 @@ function canonicalRequestStandards(standards) {
|
|
|
11038
11070
|
throw new Error("Review standards require a framework and identifier");
|
|
11039
11071
|
}
|
|
11040
11072
|
const key = assessmentStandardRefKey(standard);
|
|
11041
|
-
if (!canonical.has(key)) {
|
|
11042
|
-
canonical.set(key,
|
|
11073
|
+
if (!canonical.has(key) || input.requireBothQuestions) {
|
|
11074
|
+
canonical.set(key, {
|
|
11075
|
+
...standard,
|
|
11076
|
+
...input.requireBothQuestions ? { requireBothQuestions: true } : {}
|
|
11077
|
+
});
|
|
11043
11078
|
}
|
|
11044
11079
|
}
|
|
11045
|
-
return [...canonical.values()]
|
|
11080
|
+
return [...canonical.values()];
|
|
11046
11081
|
}
|
|
11047
11082
|
function normalizeReviewRequest(request) {
|
|
11083
|
+
if ("requireBothQuestions" in request && request.requireBothQuestions !== undefined) {
|
|
11084
|
+
throw new Error("Set requireBothQuestions on individual review standards, not the review request");
|
|
11085
|
+
}
|
|
11048
11086
|
const candidateItemsPerStandard = request.candidateItemsPerStandard ?? 1;
|
|
11049
11087
|
if (!Number.isInteger(candidateItemsPerStandard) || candidateItemsPerStandard <= 0 || candidateItemsPerStandard > TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard) {
|
|
11050
11088
|
throw new RangeError(`candidateItemsPerStandard must be a positive integer at most ${TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard}`);
|
|
@@ -11053,17 +11091,22 @@ function normalizeReviewRequest(request) {
|
|
|
11053
11091
|
if (standards.length === 0) {
|
|
11054
11092
|
throw new Error("At least one review standard is required");
|
|
11055
11093
|
}
|
|
11056
|
-
return {
|
|
11094
|
+
return {
|
|
11095
|
+
standards,
|
|
11096
|
+
candidateItemsPerStandard
|
|
11097
|
+
};
|
|
11057
11098
|
}
|
|
11058
11099
|
function reviewRequestFingerprint(request, policy) {
|
|
11059
11100
|
const normalized = normalizeReviewRequest(request);
|
|
11101
|
+
const requiredStandardKeys = normalized.standards.filter((standard) => standard.requireBothQuestions).map(assessmentStandardRefKey);
|
|
11060
11102
|
return JSON.stringify({
|
|
11061
11103
|
kind: "standards-review",
|
|
11062
11104
|
policy: {
|
|
11063
11105
|
version: policy.version
|
|
11064
11106
|
},
|
|
11065
11107
|
candidateItemsPerStandard: normalized.candidateItemsPerStandard,
|
|
11066
|
-
standardKeys: normalized.standards.map(assessmentStandardRefKey)
|
|
11108
|
+
standardKeys: normalized.standards.map(assessmentStandardRefKey),
|
|
11109
|
+
...requiredStandardKeys.length > 0 ? { requiredStandardKeys } : {}
|
|
11067
11110
|
});
|
|
11068
11111
|
}
|
|
11069
11112
|
function reviewQuestionLineItemId(parentLineItemId, itemIdentifier) {
|
|
@@ -11289,9 +11332,10 @@ function rankedCandidatesByStandard(bank, exposures) {
|
|
|
11289
11332
|
return byStandard;
|
|
11290
11333
|
}
|
|
11291
11334
|
function reviewSlots(request) {
|
|
11292
|
-
return request.standards.flatMap((standard) => Array.from({ length: request.candidateItemsPerStandard }, () => ({
|
|
11293
|
-
standard,
|
|
11294
|
-
standardKey: assessmentStandardRefKey(standard)
|
|
11335
|
+
return request.standards.flatMap((standard, servingIndex) => Array.from({ length: request.candidateItemsPerStandard }, () => ({
|
|
11336
|
+
standard: reviewStandardRef(standard),
|
|
11337
|
+
standardKey: assessmentStandardRefKey(standard),
|
|
11338
|
+
servingIndex
|
|
11295
11339
|
})));
|
|
11296
11340
|
}
|
|
11297
11341
|
function matchingCandidates(candidatesByStandard, slotCount) {
|
|
@@ -11404,7 +11448,7 @@ function fulfillment(request, candidatesByStandard, selections) {
|
|
|
11404
11448
|
const selected = selectedByStandard.get(key) ?? 0;
|
|
11405
11449
|
return selected < request.candidateItemsPerStandard ? [
|
|
11406
11450
|
{
|
|
11407
|
-
standard,
|
|
11451
|
+
standard: reviewStandardRef(standard),
|
|
11408
11452
|
requested: request.candidateItemsPerStandard,
|
|
11409
11453
|
selected,
|
|
11410
11454
|
eligible: candidatesByStandard.get(key)?.length ?? 0
|
|
@@ -11429,10 +11473,10 @@ function fulfillment(request, candidatesByStandard, selections) {
|
|
|
11429
11473
|
function selectReviewItems(input) {
|
|
11430
11474
|
const request = normalizeReviewRequest(input.request);
|
|
11431
11475
|
const candidatesByStandard = rankedCandidatesByStandard(input.bank, input.exposures);
|
|
11432
|
-
const slots = reviewSlots(request);
|
|
11476
|
+
const slots = reviewSlots(request).toSorted((left, right) => compareCodeUnits(left.standardKey, right.standardKey));
|
|
11433
11477
|
const boundedCandidates = matchingCandidates(candidatesByStandard, slots.length);
|
|
11434
11478
|
const selected = preferredDistinctMatching(slots, boundedCandidates);
|
|
11435
|
-
const selections = [...selected.entries()].toSorted(([left], [right]) => left - right).map(([index, itemIdentifier]) => ({
|
|
11479
|
+
const selections = [...selected.entries()].toSorted(([left], [right]) => slots[left].servingIndex - slots[right].servingIndex || left - right).map(([index, itemIdentifier]) => ({
|
|
11436
11480
|
standard: slots[index].standard,
|
|
11437
11481
|
itemIdentifier
|
|
11438
11482
|
}));
|
|
@@ -11571,6 +11615,9 @@ function isAssessmentScore(value) {
|
|
|
11571
11615
|
function isAssessmentStandardRef(value) {
|
|
11572
11616
|
return isRecord(value) && typeof value.framework === "string" && value.framework.length > 0 && typeof value.identifier === "string" && value.identifier.length > 0;
|
|
11573
11617
|
}
|
|
11618
|
+
function isAssessmentReviewStandard(value) {
|
|
11619
|
+
return isRecord(value) && isAssessmentStandardRef(value) && (value.requireBothQuestions === undefined || typeof value.requireBothQuestions === "boolean");
|
|
11620
|
+
}
|
|
11574
11621
|
function isReviewFulfillment(value) {
|
|
11575
11622
|
if (!isRecord(value) || value.status !== "complete" && value.status !== "partial" || !Number.isInteger(value.requestedItemCount) || !Number.isInteger(value.selectedItemCount) || !Array.isArray(value.shortages)) {
|
|
11576
11623
|
return false;
|
|
@@ -11645,7 +11692,7 @@ function isRoutedDiagnosticAttemptMetadata(value, itemSubmissions, responseVersi
|
|
|
11645
11692
|
});
|
|
11646
11693
|
}
|
|
11647
11694
|
function isReviewAttemptMetadata(value) {
|
|
11648
|
-
return isRecord(value) && typeof value.requestFingerprint === "string" && typeof value.bankRevision === "string" && Array.isArray(value.standards) && value.standards.every(
|
|
11695
|
+
return isRecord(value) && typeof value.requestFingerprint === "string" && typeof value.bankRevision === "string" && Array.isArray(value.standards) && value.standards.every(isAssessmentReviewStandard) && Number.isInteger(value.candidateItemsPerStandard) && value.requireBothQuestions === undefined && Array.isArray(value.selections) && value.selections.every((selection) => isRecord(selection) && isAssessmentStandardRef(selection.standard) && typeof selection.itemIdentifier === "string") && isReviewFulfillment(value.fulfillment);
|
|
11649
11696
|
}
|
|
11650
11697
|
function isOptionalInteger(value) {
|
|
11651
11698
|
return value === undefined || Number.isInteger(value);
|
|
@@ -12343,7 +12390,8 @@ var init_assessment_runtime2 = __esm(() => {
|
|
|
12343
12390
|
}),
|
|
12344
12391
|
StartAssessmentBaseSchema.extend({
|
|
12345
12392
|
purpose: exports_external.literal("review"),
|
|
12346
|
-
|
|
12393
|
+
requireBothQuestions: exports_external.never().optional(),
|
|
12394
|
+
standards: exports_external.array(AssessmentStandardRefSchema2.and(exports_external.object({ requireBothQuestions: exports_external.boolean().optional() }))).min(1).max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standards),
|
|
12347
12395
|
candidateItemsPerStandard: exports_external.number().int().positive().max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard).optional()
|
|
12348
12396
|
}),
|
|
12349
12397
|
StartAssessmentBaseSchema.extend({
|
|
@@ -104517,6 +104565,16 @@ var init_timeback_assessment_runtime_service = __esm(async () => {
|
|
|
104517
104565
|
};
|
|
104518
104566
|
});
|
|
104519
104567
|
if (accepted.repair) {
|
|
104568
|
+
const { metadata: metadata2 } = accepted.repair.graded;
|
|
104569
|
+
if (metadata2.purpose === "review") {
|
|
104570
|
+
reportReviewRequiredPairUnavailable(metadata2.review, metadata2.itemSubmissions.map((item) => item.itemIdentifier), (error88) => addEvent("assessment.review_required_pair_unavailable", {
|
|
104571
|
+
"app.assessment.attempt_id": params.attemptId,
|
|
104572
|
+
"app.assessment.submission_id": input.submissionId,
|
|
104573
|
+
"app.error.code": error88.code,
|
|
104574
|
+
"app.assessment.review.required_pair_failure_count": error88.failures.length,
|
|
104575
|
+
"app.assessment.review.required_pair_failures": error88.failures.map((failure) => JSON.stringify(failure))
|
|
104576
|
+
}));
|
|
104577
|
+
}
|
|
104520
104578
|
this.reconcileTranscriptChildren(accepted.repair.context, accepted.repair.graded).catch((error88) => this.recordTranscriptFailure("completion_repair", params.attemptId, error88));
|
|
104521
104579
|
}
|
|
104522
104580
|
if (accepted.emission) {
|