@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.
Files changed (3) hide show
  1. package/dist/cli.js +72 -14
  2. package/dist/server.js +72 -14
  3. 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.1",
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, standard);
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()].toSorted((left, right) => compareCodeUnits(assessmentStandardRefKey(left), assessmentStandardRefKey(right)));
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 { standards, candidateItemsPerStandard };
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(isAssessmentStandardRef) && Number.isInteger(value.candidateItemsPerStandard) && Array.isArray(value.selections) && value.selections.every((selection) => isRecord(selection) && isAssessmentStandardRef(selection.standard) && typeof selection.itemIdentifier === "string") && isReviewFulfillment(value.fulfillment);
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
- standards: exports_external.array(AssessmentStandardRefSchema2).min(1).max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standards),
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.1",
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, standard);
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()].toSorted((left, right) => compareCodeUnits(assessmentStandardRefKey(left), assessmentStandardRefKey(right)));
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 { standards, candidateItemsPerStandard };
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(isAssessmentStandardRef) && Number.isInteger(value.candidateItemsPerStandard) && Array.isArray(value.selections) && value.selections.every((selection) => isRecord(selection) && isAssessmentStandardRef(selection.standard) && typeof selection.itemIdentifier === "string") && isReviewFulfillment(value.fulfillment);
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
- standards: exports_external.array(AssessmentStandardRefSchema2).min(1).max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standards),
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/sandbox",
3
- "version": "0.10.1-beta.1",
3
+ "version": "0.10.1-beta.3",
4
4
  "description": "Local development server for Playcademy game development",
5
5
  "type": "module",
6
6
  "exports": {