@plasius/learning 0.2.19 → 0.2.21
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/README.md +55 -0
- package/dist/index.cjs +333 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +209 -1
- package/dist/index.d.ts +209 -1
- package/dist/index.js +310 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,6 +54,61 @@ const result = calculateAssessment(rubric, [
|
|
|
54
54
|
console.log(result.score, result.completed);
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
## Bind contextual and spoken help
|
|
58
|
+
|
|
59
|
+
Contextual-help identifiers are immutable module/manifest references rather
|
|
60
|
+
than free-form learner text. Voice consent is separate from general AI consent,
|
|
61
|
+
and version one permits private-edge transcription only.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import {
|
|
65
|
+
CONTEXTUAL_HELP_CONTRACT_VERSION_V1,
|
|
66
|
+
assertValidContextualHelpIdentifier,
|
|
67
|
+
type ContextualHelpIdentifierV1,
|
|
68
|
+
} from "@plasius/learning";
|
|
69
|
+
|
|
70
|
+
const help: ContextualHelpIdentifierV1 = {
|
|
71
|
+
schemaVersion: "1",
|
|
72
|
+
contractVersion: CONTEXTUAL_HELP_CONTRACT_VERSION_V1,
|
|
73
|
+
kind: "command",
|
|
74
|
+
moduleId: "junior-coder.road-hopper-rally",
|
|
75
|
+
moduleVersion: "1.1.0",
|
|
76
|
+
manifestVersion: "1.0.0",
|
|
77
|
+
helpId: "command.draw-lane",
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
assertValidContextualHelpIdentifier(help);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The package also exports `GuardianVoiceConsentV1`,
|
|
84
|
+
`VoiceHelpAvailabilityV1`, bounded voice question metadata/results and
|
|
85
|
+
`CanonicalSpokenHelpDescriptorV1`. It does not record audio, persist consent,
|
|
86
|
+
call a transcription or synthesis provider, or evaluate runtime rollout flags.
|
|
87
|
+
|
|
88
|
+
## Validate a Guardian-approved static project
|
|
89
|
+
|
|
90
|
+
The publishing contracts cover only immutable evidence and safe render models.
|
|
91
|
+
HTTP, persistence, identity checks, scanning implementations and hosting remain
|
|
92
|
+
consumer responsibilities. A public renderer must consume the allow-listed
|
|
93
|
+
`renderModel`; it must never execute learner source.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import {
|
|
97
|
+
assertValidStaticProjectGuardianApproval,
|
|
98
|
+
assertValidStaticProjectPublication,
|
|
99
|
+
assertValidStaticProjectSnapshot,
|
|
100
|
+
} from "@plasius/learning";
|
|
101
|
+
|
|
102
|
+
assertValidStaticProjectSnapshot(snapshot);
|
|
103
|
+
assertValidStaticProjectGuardianApproval(approval);
|
|
104
|
+
assertValidStaticProjectPublication(publication);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The version-one contract supports the three launch web projects, requires a
|
|
108
|
+
score of at least 80 plus mandatory safety evidence, records all eight scanner
|
|
109
|
+
checks, binds adult approval to the exact snapshot digest, and requires an
|
|
110
|
+
unlisted HTTPS URL with a random slug and explicit expiry.
|
|
111
|
+
|
|
57
112
|
## Validate mission authoring
|
|
58
113
|
|
|
59
114
|
Mission authoring is additive to the immutable catalog. A bundle contains
|
package/dist/index.cjs
CHANGED
|
@@ -22,6 +22,10 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
ADVENTURE_MISSION_PLANNER_MISSION_ONE_AUTHORING_V1: () => ADVENTURE_MISSION_PLANNER_MISSION_ONE_AUTHORING_V1,
|
|
24
24
|
BEACON_BOT_MISSION_ONE_AUTHORING_V1: () => BEACON_BOT_MISSION_ONE_AUTHORING_V1,
|
|
25
|
+
CONTEXTUAL_HELP_CONTRACT_VERSION_V1: () => CONTEXTUAL_HELP_CONTRACT_VERSION_V1,
|
|
26
|
+
CONTEXTUAL_HELP_KINDS_V1: () => CONTEXTUAL_HELP_KINDS_V1,
|
|
27
|
+
CONTEXTUAL_VOICE_INTENTS_V1: () => CONTEXTUAL_VOICE_INTENTS_V1,
|
|
28
|
+
CONTEXTUAL_VOICE_SUGGESTED_ACTIONS_V1: () => CONTEXTUAL_VOICE_SUGGESTED_ACTIONS_V1,
|
|
25
29
|
CREATURE_CARE_DASHBOARD_MISSION_ONE_AUTHORING_V1: () => CREATURE_CARE_DASHBOARD_MISSION_ONE_AUTHORING_V1,
|
|
26
30
|
DANCE_ROVER_MISSION_ONE_AUTHORING_V1: () => DANCE_ROVER_MISSION_ONE_AUTHORING_V1,
|
|
27
31
|
JUNIOR_CODER_MISSION_STAGE_ORDER_V1: () => JUNIOR_CODER_MISSION_STAGE_ORDER_V1,
|
|
@@ -42,15 +46,33 @@ __export(index_exports, {
|
|
|
42
46
|
SERVO_CREATURE_MISSION_ONE_AUTHORING_V1: () => SERVO_CREATURE_MISSION_ONE_AUTHORING_V1,
|
|
43
47
|
SKYWING_SPRINT_MISSION_ONE_AUTHORING_V1: () => SKYWING_SPRINT_MISSION_ONE_AUTHORING_V1,
|
|
44
48
|
STAR_DEFENDER_SQUADRON_MISSION_ONE_AUTHORING_V1: () => STAR_DEFENDER_SQUADRON_MISSION_ONE_AUTHORING_V1,
|
|
49
|
+
STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1: () => STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1,
|
|
50
|
+
STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1: () => STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1,
|
|
51
|
+
STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1: () => STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1,
|
|
52
|
+
STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1: () => STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1,
|
|
53
|
+
STATIC_PROJECT_SAFETY_CHECK_IDS_V1: () => STATIC_PROJECT_SAFETY_CHECK_IDS_V1,
|
|
54
|
+
STATIC_PROJECT_SCANNER_VERSION_V1: () => STATIC_PROJECT_SCANNER_VERSION_V1,
|
|
45
55
|
VIBE_BUG_DETECTIVE_MISSION_ONE_AUTHORING_V1: () => VIBE_BUG_DETECTIVE_MISSION_ONE_AUTHORING_V1,
|
|
46
56
|
VIBE_GAME_REMIX_LAB_MISSION_ONE_AUTHORING_V1: () => VIBE_GAME_REMIX_LAB_MISSION_ONE_AUTHORING_V1,
|
|
47
57
|
VIBE_IDEA_STUDIO_MISSION_ONE_AUTHORING_V1: () => VIBE_IDEA_STUDIO_MISSION_ONE_AUTHORING_V1,
|
|
58
|
+
assertValidCanonicalSpokenHelpDescriptor: () => assertValidCanonicalSpokenHelpDescriptor,
|
|
59
|
+
assertValidContextualHelpIdentifier: () => assertValidContextualHelpIdentifier,
|
|
60
|
+
assertValidContextualVoiceQuestionMetadata: () => assertValidContextualVoiceQuestionMetadata,
|
|
61
|
+
assertValidContextualVoiceQuestionResult: () => assertValidContextualVoiceQuestionResult,
|
|
62
|
+
assertValidGuardianVoiceConsent: () => assertValidGuardianVoiceConsent,
|
|
48
63
|
assertValidLearningPath: () => assertValidLearningPath,
|
|
49
64
|
assertValidMissionAuthoringBundle: () => assertValidMissionAuthoringBundle,
|
|
65
|
+
assertValidStaticProjectGuardianApproval: () => assertValidStaticProjectGuardianApproval,
|
|
66
|
+
assertValidStaticProjectPublication: () => assertValidStaticProjectPublication,
|
|
67
|
+
assertValidStaticProjectSnapshot: () => assertValidStaticProjectSnapshot,
|
|
68
|
+
assertValidVoiceHelpAvailability: () => assertValidVoiceHelpAvailability,
|
|
50
69
|
calculateAssessment: () => calculateAssessment,
|
|
51
70
|
validateAssessmentRubric: () => validateAssessmentRubric,
|
|
52
71
|
validateLearningPath: () => validateLearningPath,
|
|
53
|
-
validateMissionAuthoringBundle: () => validateMissionAuthoringBundle
|
|
72
|
+
validateMissionAuthoringBundle: () => validateMissionAuthoringBundle,
|
|
73
|
+
validateStaticProjectGuardianApproval: () => validateStaticProjectGuardianApproval,
|
|
74
|
+
validateStaticProjectPublication: () => validateStaticProjectPublication,
|
|
75
|
+
validateStaticProjectSnapshot: () => validateStaticProjectSnapshot
|
|
54
76
|
});
|
|
55
77
|
module.exports = __toCommonJS(index_exports);
|
|
56
78
|
|
|
@@ -627,6 +649,293 @@ var JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT = JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1
|
|
|
627
649
|
// src/contracts.ts
|
|
628
650
|
var MISSION_AUTHORING_CONTRACT_VERSION_V1 = "1.0.0";
|
|
629
651
|
|
|
652
|
+
// src/contextual-help.ts
|
|
653
|
+
var CONTEXTUAL_HELP_CONTRACT_VERSION_V1 = "1.0.0";
|
|
654
|
+
var CONTEXTUAL_HELP_KINDS_V1 = Object.freeze([
|
|
655
|
+
"command",
|
|
656
|
+
"visual-block",
|
|
657
|
+
"generated-code",
|
|
658
|
+
"assessment-diagnostic"
|
|
659
|
+
]);
|
|
660
|
+
var CONTEXTUAL_VOICE_INTENTS_V1 = Object.freeze([
|
|
661
|
+
"describe-command",
|
|
662
|
+
"describe-inputs",
|
|
663
|
+
"show-example",
|
|
664
|
+
"explain-assessment-failure",
|
|
665
|
+
"suggest-next-experiment",
|
|
666
|
+
"repeat",
|
|
667
|
+
"stop",
|
|
668
|
+
"unresolved"
|
|
669
|
+
]);
|
|
670
|
+
var CONTEXTUAL_VOICE_SUGGESTED_ACTIONS_V1 = Object.freeze([
|
|
671
|
+
"open-help",
|
|
672
|
+
"insert-example",
|
|
673
|
+
"show-inputs",
|
|
674
|
+
"show-assessment-evidence",
|
|
675
|
+
"try-next-experiment",
|
|
676
|
+
"repeat",
|
|
677
|
+
"stop",
|
|
678
|
+
"type-question"
|
|
679
|
+
]);
|
|
680
|
+
var OPAQUE_ID = /^[a-z0-9]+(?:[._:-][a-z0-9]+)*$/u;
|
|
681
|
+
var SEMVER = /^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][A-Za-z0-9.-]+)?$/u;
|
|
682
|
+
var SHA_256 = /^sha256:[a-f0-9]{64}$/u;
|
|
683
|
+
var LOCALE = /^[a-z]{2,3}(?:-[A-Z]{2})?$/u;
|
|
684
|
+
var MEDIA_TYPE = /^audio\/[a-z0-9.+-]+$/u;
|
|
685
|
+
function containsDisallowedControlCharacter(value) {
|
|
686
|
+
return [...value].some((character) => {
|
|
687
|
+
const code = character.codePointAt(0) ?? 0;
|
|
688
|
+
return code <= 8 || code === 11 || code === 12 || code >= 14 && code <= 31 || code === 127;
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
function requireOpaqueId(value, label, maximum = 160) {
|
|
692
|
+
if (value.length === 0 || value.length > maximum || !OPAQUE_ID.test(value)) {
|
|
693
|
+
throw new Error(`${label} must be a bounded opaque identifier.`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
function requireSemver(value, label) {
|
|
697
|
+
if (!SEMVER.test(value)) {
|
|
698
|
+
throw new Error(`${label} must be an immutable semantic version.`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
function requireIsoTimestamp(value, label) {
|
|
702
|
+
if (!/^\d{4}-\d{2}-\d{2}T/u.test(value) || !Number.isFinite(Date.parse(value))) {
|
|
703
|
+
throw new Error(`${label} must be an ISO-8601 timestamp.`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
function assertValidContextualHelpIdentifier(value) {
|
|
707
|
+
if (value.schemaVersion !== "1") {
|
|
708
|
+
throw new Error("schemaVersion must be 1.");
|
|
709
|
+
}
|
|
710
|
+
if (value.contractVersion !== CONTEXTUAL_HELP_CONTRACT_VERSION_V1) {
|
|
711
|
+
throw new Error("contractVersion is unsupported.");
|
|
712
|
+
}
|
|
713
|
+
if (!CONTEXTUAL_HELP_KINDS_V1.includes(value.kind)) {
|
|
714
|
+
throw new Error("kind is unsupported.");
|
|
715
|
+
}
|
|
716
|
+
requireOpaqueId(value.moduleId, "moduleId");
|
|
717
|
+
requireSemver(value.moduleVersion, "moduleVersion");
|
|
718
|
+
requireSemver(value.manifestVersion, "manifestVersion");
|
|
719
|
+
requireOpaqueId(value.helpId, "helpId");
|
|
720
|
+
}
|
|
721
|
+
function assertValidGuardianVoiceConsent(value) {
|
|
722
|
+
if (value.schemaVersion !== "1") {
|
|
723
|
+
throw new Error("schemaVersion must be 1.");
|
|
724
|
+
}
|
|
725
|
+
requireOpaqueId(value.actorAccountId, "actorAccountId");
|
|
726
|
+
requireOpaqueId(value.subjectAccountId, "subjectAccountId");
|
|
727
|
+
requireSemver(value.policyVersion, "policyVersion");
|
|
728
|
+
if (value.state !== "granted" && value.state !== "withdrawn") {
|
|
729
|
+
throw new Error("state must be granted or withdrawn.");
|
|
730
|
+
}
|
|
731
|
+
if (value.permittedProcessingRoute !== "private-edge-only") {
|
|
732
|
+
throw new Error("permittedProcessingRoute must be private-edge-only.");
|
|
733
|
+
}
|
|
734
|
+
requireIsoTimestamp(value.recordedAt, "recordedAt");
|
|
735
|
+
}
|
|
736
|
+
function assertValidContextualVoiceQuestionMetadata(value) {
|
|
737
|
+
assertValidContextualHelpIdentifier(value.help);
|
|
738
|
+
if (!LOCALE.test(value.locale)) throw new Error("locale is invalid.");
|
|
739
|
+
if (!MEDIA_TYPE.test(value.mediaType)) throw new Error("mediaType is invalid.");
|
|
740
|
+
if (!Number.isInteger(value.durationMs) || value.durationMs < 1 || value.durationMs > 1e4) {
|
|
741
|
+
throw new Error("durationMs must be between 1 and 10000.");
|
|
742
|
+
}
|
|
743
|
+
if (!Number.isInteger(value.audioBytes) || value.audioBytes < 1 || value.audioBytes > 2097152) {
|
|
744
|
+
throw new Error("audioBytes must be between 1 and 2097152.");
|
|
745
|
+
}
|
|
746
|
+
if (value.assessmentEvidenceId !== void 0) {
|
|
747
|
+
requireOpaqueId(value.assessmentEvidenceId, "assessmentEvidenceId");
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function assertValidVoiceHelpAvailability(value) {
|
|
751
|
+
if (value.schemaVersion !== "1") throw new Error("schemaVersion must be 1.");
|
|
752
|
+
if (value.questionProcessingRoute !== "private-edge-only") {
|
|
753
|
+
throw new Error("questionProcessingRoute must be private-edge-only.");
|
|
754
|
+
}
|
|
755
|
+
if (value.guardianVoiceConsentRequired !== true) {
|
|
756
|
+
throw new Error("guardianVoiceConsentRequired must remain true.");
|
|
757
|
+
}
|
|
758
|
+
if (value.maximumRecordingDurationMs !== 1e4 || value.maximumAudioBytes !== 2097152 || value.rawAudioRetention !== "request-memory-only" || value.transcriptRetention !== "request-memory-only") {
|
|
759
|
+
throw new Error("Voice limits and transient retention are immutable in version one.");
|
|
760
|
+
}
|
|
761
|
+
if (value.microphoneAvailable !== (value.microphoneReason === "available")) {
|
|
762
|
+
throw new Error("microphoneReason must match microphone availability.");
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
function assertValidCanonicalSpokenHelpDescriptor(value) {
|
|
766
|
+
if (value.schemaVersion !== "1") throw new Error("schemaVersion must be 1.");
|
|
767
|
+
assertValidContextualHelpIdentifier(value.help);
|
|
768
|
+
requireOpaqueId(value.canonicalTextId, "canonicalTextId");
|
|
769
|
+
if (!SHA_256.test(value.authoritativeTextDigest)) {
|
|
770
|
+
throw new Error("authoritativeTextDigest must be a SHA-256 digest.");
|
|
771
|
+
}
|
|
772
|
+
if (!LOCALE.test(value.locale)) throw new Error("locale is invalid.");
|
|
773
|
+
requireOpaqueId(value.voiceProfile, "voiceProfile");
|
|
774
|
+
requireSemver(value.pronunciationVersion, "pronunciationVersion");
|
|
775
|
+
if (value.utteranceClass !== "system-generic" || value.sharingScope !== "global" || value.reuse !== "exact-only" || value.containsPersonalData !== false || value.containsLearnerContent !== false) {
|
|
776
|
+
throw new Error("Canonical spoken help must use global system-generic exact-only reuse.");
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
function assertValidContextualVoiceQuestionResult(value) {
|
|
780
|
+
if (value.schemaVersion !== "1") throw new Error("schemaVersion must be 1.");
|
|
781
|
+
assertValidContextualHelpIdentifier(value.help);
|
|
782
|
+
if (!CONTEXTUAL_VOICE_INTENTS_V1.includes(value.intent)) {
|
|
783
|
+
throw new Error("intent is unsupported.");
|
|
784
|
+
}
|
|
785
|
+
if (value.transcriptRetention !== "request-memory-only") {
|
|
786
|
+
throw new Error("transcriptRetention must be request-memory-only.");
|
|
787
|
+
}
|
|
788
|
+
if (value.status !== "resolved" && value.status !== "suggestions" && value.status !== "stopped") {
|
|
789
|
+
throw new Error("status is unsupported.");
|
|
790
|
+
}
|
|
791
|
+
if (value.transientTranscript.length > 500 || containsDisallowedControlCharacter(value.transientTranscript)) {
|
|
792
|
+
throw new Error("transientTranscript is invalid.");
|
|
793
|
+
}
|
|
794
|
+
if (value.answer) {
|
|
795
|
+
requireOpaqueId(value.answer.helpId, "answer.helpId");
|
|
796
|
+
if (value.answer.source !== "module-documentation" && value.answer.source !== "assessment-evidence" && value.answer.source !== "authored-fallback" || value.answer.text.length === 0 || value.answer.text.length > 800 || containsDisallowedControlCharacter(value.answer.text)) {
|
|
797
|
+
throw new Error("answer.text is invalid.");
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (value.suggestedActions.some(
|
|
801
|
+
(action) => !CONTEXTUAL_VOICE_SUGGESTED_ACTIONS_V1.includes(action)
|
|
802
|
+
)) {
|
|
803
|
+
throw new Error("suggestedActions contains an unsupported action.");
|
|
804
|
+
}
|
|
805
|
+
if (value.mayAssignScore !== false || value.mayAwardReward !== false || value.mayPublish !== false || value.mayControlHardware !== false) {
|
|
806
|
+
throw new Error("mayAssignScore, reward, publish and hardware authority must remain false.");
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// src/publishing.ts
|
|
811
|
+
var STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1 = "1.0.0";
|
|
812
|
+
var STATIC_PROJECT_SCANNER_VERSION_V1 = "junior-coder-static-scan-v1";
|
|
813
|
+
var STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1 = "guardian-static-publication-v1";
|
|
814
|
+
var STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1 = 90;
|
|
815
|
+
var STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1 = 8e3;
|
|
816
|
+
var STATIC_PROJECT_SAFETY_CHECK_IDS_V1 = [
|
|
817
|
+
"allow-listed-source",
|
|
818
|
+
"no-personal-details",
|
|
819
|
+
"no-external-network",
|
|
820
|
+
"no-executable-markup",
|
|
821
|
+
"no-transmitting-forms",
|
|
822
|
+
"no-uploads-or-embeds",
|
|
823
|
+
"no-trackers-or-advertising",
|
|
824
|
+
"no-account-identifiers"
|
|
825
|
+
];
|
|
826
|
+
var DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/u;
|
|
827
|
+
var IDENTIFIER_PATTERN = /^(?:account|approval|publication|snapshot)_[A-Za-z0-9_-]{20,128}$/u;
|
|
828
|
+
var VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][A-Za-z0-9.-]+)?$/u;
|
|
829
|
+
var RANDOM_SLUG_PATTERN = /^[A-Za-z0-9_-]{40,128}$/u;
|
|
830
|
+
function validDate(value) {
|
|
831
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
832
|
+
}
|
|
833
|
+
function allSafetyChecksPresent(scan) {
|
|
834
|
+
if (!Array.isArray(scan.checks) || scan.checks.length !== STATIC_PROJECT_SAFETY_CHECK_IDS_V1.length) {
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
const supplied = new Set(scan.checks.map((check) => check.id));
|
|
838
|
+
return STATIC_PROJECT_SAFETY_CHECK_IDS_V1.every((id) => supplied.has(id)) && scan.checks.every((check) => check.passed === true);
|
|
839
|
+
}
|
|
840
|
+
function safeAdventureRender(value) {
|
|
841
|
+
const headings = ["Moonbase Missions", "Forest Rescue Plans", "Ocean Quest Board"];
|
|
842
|
+
const titles = ["Find the moon crystal", "Guide the lost firefly", "Map the coral garden"];
|
|
843
|
+
const days = ["Saturday", "Sunday", "School holiday"];
|
|
844
|
+
const messages = ["Choose a day", "Add a mission title", "Mission ready!"];
|
|
845
|
+
return headings.includes(value.heading) && Array.isArray(value.missions) && value.missions.length >= 1 && value.missions.length <= 3 && value.missions.every((mission2) => titles.includes(mission2.title) && days.includes(mission2.day)) && messages.includes(value.validationMessage) && value.savedAcrossRestart === true && value.accessibleSummaryEnabled === true;
|
|
846
|
+
}
|
|
847
|
+
function safeCreatureRender(value) {
|
|
848
|
+
return ["Moon Moth", "Cloud Cat", "Pebble Dragon"].includes(value.creature) && ["Resting", "Ready to play", "Snack time"].includes(value.status) && [5, 10, 15].includes(value.timerSeconds) && ["single", "cosy-grid", "wide-grid"].includes(value.layout) && value.reducedMotion === true;
|
|
849
|
+
}
|
|
850
|
+
function safeRobotRender(value) {
|
|
851
|
+
return ["scan", "hold-position", "return-to-base"].includes(value.command) && value.safetyConfirmed === true && [1, 2, 4].includes(value.telemetryRate) && ["line", "bars", "text-only"].includes(value.chartMode) && value.serialSimulation === true && ["SCANNING", "HOLDING", "RETURNING"].includes(value.state);
|
|
852
|
+
}
|
|
853
|
+
function validateStaticProjectSnapshot(value) {
|
|
854
|
+
const issues = [];
|
|
855
|
+
if (value.schemaVersion !== "1") issues.push("invalid-schema-version");
|
|
856
|
+
if (value.contractVersion !== STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1) {
|
|
857
|
+
issues.push("invalid-contract-version");
|
|
858
|
+
}
|
|
859
|
+
if (!IDENTIFIER_PATTERN.test(value.snapshotId) || !IDENTIFIER_PATTERN.test(value.subjectAccountId)) {
|
|
860
|
+
issues.push("invalid-identifier");
|
|
861
|
+
}
|
|
862
|
+
if (!value.moduleId.startsWith("junior-coder.") || value.moduleId !== `junior-coder.${value.moduleSlug}`) {
|
|
863
|
+
issues.push("invalid-module");
|
|
864
|
+
}
|
|
865
|
+
if (!VERSION_PATTERN.test(value.moduleVersion)) issues.push("invalid-version");
|
|
866
|
+
if (!DIGEST_PATTERN.test(value.sourceDigest)) issues.push("invalid-source-digest");
|
|
867
|
+
if (!DIGEST_PATTERN.test(value.snapshotDigest)) issues.push("invalid-snapshot-digest");
|
|
868
|
+
if (!Number.isInteger(value.sourceCharacterCount) || value.sourceCharacterCount < 1 || value.sourceCharacterCount > STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1) {
|
|
869
|
+
issues.push("invalid-source-size");
|
|
870
|
+
}
|
|
871
|
+
if (!Number.isInteger(value.assessmentScore) || value.assessmentScore < 80 || value.assessmentScore > 100) {
|
|
872
|
+
issues.push("assessment-score-incomplete");
|
|
873
|
+
}
|
|
874
|
+
if (value.mandatorySafetyPassed !== true) issues.push("mandatory-safety-missing");
|
|
875
|
+
if (value.scan?.passed !== true || value.scan?.scannerVersion !== STATIC_PROJECT_SCANNER_VERSION_V1) {
|
|
876
|
+
issues.push("scan-not-passed");
|
|
877
|
+
}
|
|
878
|
+
if (!value.scan || !allSafetyChecksPresent(value.scan)) issues.push("scan-checks-incomplete");
|
|
879
|
+
if (value.moduleSlug !== value.renderModel?.kind) issues.push("module-render-model-mismatch");
|
|
880
|
+
const renderSafe = value.renderModel?.kind === "adventure-mission-planner" ? safeAdventureRender(value.renderModel) : value.renderModel?.kind === "creature-care-dashboard" ? safeCreatureRender(value.renderModel) : value.renderModel?.kind === "robot-mission-control" ? safeRobotRender(value.renderModel) : false;
|
|
881
|
+
if (!renderSafe) issues.push("unsafe-render-model");
|
|
882
|
+
if (value.state !== "pending-review" || !validDate(value.createdAt)) issues.push("invalid-created-at");
|
|
883
|
+
return [...new Set(issues)];
|
|
884
|
+
}
|
|
885
|
+
function assertValidStaticProjectSnapshot(value) {
|
|
886
|
+
const issues = validateStaticProjectSnapshot(value);
|
|
887
|
+
if (issues.length > 0) throw new Error(`Invalid static project snapshot: ${issues.join(", ")}`);
|
|
888
|
+
}
|
|
889
|
+
function validateStaticProjectGuardianApproval(value) {
|
|
890
|
+
const issues = [];
|
|
891
|
+
if (value.schemaVersion !== "1") issues.push("invalid-schema-version");
|
|
892
|
+
if (!IDENTIFIER_PATTERN.test(value.approvalId) || !IDENTIFIER_PATTERN.test(value.snapshotId) || !IDENTIFIER_PATTERN.test(value.guardianActorAccountId)) {
|
|
893
|
+
issues.push("invalid-identifier");
|
|
894
|
+
}
|
|
895
|
+
if (!DIGEST_PATTERN.test(value.snapshotDigest)) issues.push("invalid-snapshot-digest");
|
|
896
|
+
if (value.statementVersion !== STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1) {
|
|
897
|
+
issues.push("invalid-approval-statement");
|
|
898
|
+
}
|
|
899
|
+
if (!validDate(value.approvedAt)) issues.push("invalid-approved-at");
|
|
900
|
+
return [...new Set(issues)];
|
|
901
|
+
}
|
|
902
|
+
function assertValidStaticProjectGuardianApproval(value) {
|
|
903
|
+
const issues = validateStaticProjectGuardianApproval(value);
|
|
904
|
+
if (issues.length > 0) throw new Error(`Invalid static project approval: ${issues.join(", ")}`);
|
|
905
|
+
}
|
|
906
|
+
function validateStaticProjectPublication(value) {
|
|
907
|
+
const issues = [];
|
|
908
|
+
if (value.schemaVersion !== "1") issues.push("invalid-schema-version");
|
|
909
|
+
if (!IDENTIFIER_PATTERN.test(value.publicationId) || !IDENTIFIER_PATTERN.test(value.snapshotId) || !IDENTIFIER_PATTERN.test(value.approvalId)) {
|
|
910
|
+
issues.push("invalid-identifier");
|
|
911
|
+
}
|
|
912
|
+
if (!DIGEST_PATTERN.test(value.snapshotDigest)) issues.push("invalid-snapshot-digest");
|
|
913
|
+
if (!RANDOM_SLUG_PATTERN.test(value.randomSlug)) issues.push("invalid-random-slug");
|
|
914
|
+
let parsedUrl;
|
|
915
|
+
try {
|
|
916
|
+
parsedUrl = new URL(value.publicUrl);
|
|
917
|
+
} catch {
|
|
918
|
+
parsedUrl = void 0;
|
|
919
|
+
}
|
|
920
|
+
if (!parsedUrl || parsedUrl.protocol !== "https:" || parsedUrl.username || parsedUrl.password) {
|
|
921
|
+
issues.push("invalid-public-url");
|
|
922
|
+
}
|
|
923
|
+
if (!parsedUrl?.pathname.endsWith(`/${value.randomSlug}`)) issues.push("public-url-slug-mismatch");
|
|
924
|
+
if (value.state !== "published") issues.push("published-state-required");
|
|
925
|
+
if (!validDate(value.publishedAt)) issues.push("invalid-published-at");
|
|
926
|
+
if (!validDate(value.expiresAt) || validDate(value.publishedAt) && Date.parse(value.expiresAt) <= Date.parse(value.publishedAt)) {
|
|
927
|
+
issues.push("invalid-publication-expiry");
|
|
928
|
+
}
|
|
929
|
+
if (value.renewedAt !== void 0 && !validDate(value.renewedAt) || value.unpublishedAt !== void 0 && !validDate(value.unpublishedAt)) {
|
|
930
|
+
issues.push("invalid-lifecycle-timestamp");
|
|
931
|
+
}
|
|
932
|
+
return [...new Set(issues)];
|
|
933
|
+
}
|
|
934
|
+
function assertValidStaticProjectPublication(value) {
|
|
935
|
+
const issues = validateStaticProjectPublication(value);
|
|
936
|
+
if (issues.length > 0) throw new Error(`Invalid static project publication: ${issues.join(", ")}`);
|
|
937
|
+
}
|
|
938
|
+
|
|
630
939
|
// src/rubric-validation.ts
|
|
631
940
|
var DIMENSION_TOTALS = {
|
|
632
941
|
structure: 20,
|
|
@@ -6687,6 +6996,10 @@ ${summary}`);
|
|
|
6687
6996
|
0 && (module.exports = {
|
|
6688
6997
|
ADVENTURE_MISSION_PLANNER_MISSION_ONE_AUTHORING_V1,
|
|
6689
6998
|
BEACON_BOT_MISSION_ONE_AUTHORING_V1,
|
|
6999
|
+
CONTEXTUAL_HELP_CONTRACT_VERSION_V1,
|
|
7000
|
+
CONTEXTUAL_HELP_KINDS_V1,
|
|
7001
|
+
CONTEXTUAL_VOICE_INTENTS_V1,
|
|
7002
|
+
CONTEXTUAL_VOICE_SUGGESTED_ACTIONS_V1,
|
|
6690
7003
|
CREATURE_CARE_DASHBOARD_MISSION_ONE_AUTHORING_V1,
|
|
6691
7004
|
DANCE_ROVER_MISSION_ONE_AUTHORING_V1,
|
|
6692
7005
|
JUNIOR_CODER_MISSION_STAGE_ORDER_V1,
|
|
@@ -6707,14 +7020,32 @@ ${summary}`);
|
|
|
6707
7020
|
SERVO_CREATURE_MISSION_ONE_AUTHORING_V1,
|
|
6708
7021
|
SKYWING_SPRINT_MISSION_ONE_AUTHORING_V1,
|
|
6709
7022
|
STAR_DEFENDER_SQUADRON_MISSION_ONE_AUTHORING_V1,
|
|
7023
|
+
STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1,
|
|
7024
|
+
STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1,
|
|
7025
|
+
STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1,
|
|
7026
|
+
STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1,
|
|
7027
|
+
STATIC_PROJECT_SAFETY_CHECK_IDS_V1,
|
|
7028
|
+
STATIC_PROJECT_SCANNER_VERSION_V1,
|
|
6710
7029
|
VIBE_BUG_DETECTIVE_MISSION_ONE_AUTHORING_V1,
|
|
6711
7030
|
VIBE_GAME_REMIX_LAB_MISSION_ONE_AUTHORING_V1,
|
|
6712
7031
|
VIBE_IDEA_STUDIO_MISSION_ONE_AUTHORING_V1,
|
|
7032
|
+
assertValidCanonicalSpokenHelpDescriptor,
|
|
7033
|
+
assertValidContextualHelpIdentifier,
|
|
7034
|
+
assertValidContextualVoiceQuestionMetadata,
|
|
7035
|
+
assertValidContextualVoiceQuestionResult,
|
|
7036
|
+
assertValidGuardianVoiceConsent,
|
|
6713
7037
|
assertValidLearningPath,
|
|
6714
7038
|
assertValidMissionAuthoringBundle,
|
|
7039
|
+
assertValidStaticProjectGuardianApproval,
|
|
7040
|
+
assertValidStaticProjectPublication,
|
|
7041
|
+
assertValidStaticProjectSnapshot,
|
|
7042
|
+
assertValidVoiceHelpAvailability,
|
|
6715
7043
|
calculateAssessment,
|
|
6716
7044
|
validateAssessmentRubric,
|
|
6717
7045
|
validateLearningPath,
|
|
6718
|
-
validateMissionAuthoringBundle
|
|
7046
|
+
validateMissionAuthoringBundle,
|
|
7047
|
+
validateStaticProjectGuardianApproval,
|
|
7048
|
+
validateStaticProjectPublication,
|
|
7049
|
+
validateStaticProjectSnapshot
|
|
6719
7050
|
});
|
|
6720
7051
|
//# sourceMappingURL=index.cjs.map
|