@thanh01.pmt/curriculum-kit 1.0.13 → 1.0.14
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/gateSettings-DKXRztJy.d.cts +119 -0
- package/dist/gateSettings-DKXRztJy.d.ts +119 -0
- package/dist/index.cjs +511 -1178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.mjs +512 -1155
- package/dist/index.mjs.map +1 -1
- package/dist/standards/index.d.cts +2 -2
- package/dist/standards/index.d.ts +2 -2
- package/dist/{standardsCoverageGate-BWAkXY76.d.cts → standardsCoverageGate-CsUNzv6C.d.cts} +1 -1
- package/dist/{standardsCoverageGate-BWAkXY76.d.ts → standardsCoverageGate-CsUNzv6C.d.ts} +1 -1
- package/dist/workflow/index.d.cts +298 -7
- package/dist/workflow/index.d.ts +298 -7
- package/package.json +1 -1
- package/dist/index-B8lOdFuz.d.ts +0 -414
- package/dist/index-DhxvfPoW.d.cts +0 -414
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,6 @@ import { createClient } from '@supabase/supabase-js';
|
|
|
12
12
|
import { fileURLToPath } from 'url';
|
|
13
13
|
import { jsonrepair } from 'jsonrepair';
|
|
14
14
|
import { Octokit } from '@octokit/rest';
|
|
15
|
-
import { defineHook, getStepMetadata, RetryableError, sleep } from 'workflow';
|
|
16
15
|
|
|
17
16
|
var __defProp = Object.defineProperty;
|
|
18
17
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -14661,1159 +14660,233 @@ template_contract: "artifact-template-v1"
|
|
|
14661
14660
|
timestamp: dateStr
|
|
14662
14661
|
};
|
|
14663
14662
|
}
|
|
14664
|
-
async function withRateLimitBackoff(options) {
|
|
14665
|
-
let attempt = 1;
|
|
14666
|
-
try {
|
|
14667
|
-
const meta = getStepMetadata();
|
|
14668
|
-
if (meta && typeof meta.attempt === "number") {
|
|
14669
|
-
attempt = meta.attempt;
|
|
14670
|
-
}
|
|
14671
|
-
} catch {
|
|
14672
|
-
}
|
|
14673
|
-
try {
|
|
14674
|
-
return await options.fn();
|
|
14675
|
-
} catch (error) {
|
|
14676
|
-
const errorMessage = error?.message || String(error);
|
|
14677
|
-
const status = error?.status || error?.statusCode || error?.response?.status;
|
|
14678
|
-
const isRateLimited = status === 429 || errorMessage.includes("429") || errorMessage.toLowerCase().includes("rate limit") || errorMessage.toLowerCase().includes("resource exhausted") || errorMessage.toLowerCase().includes("quota exceeded");
|
|
14679
|
-
const isTransientError = status === 500 || status === 502 || status === 503 || status === 504 || errorMessage.includes("fetch failed") || errorMessage.includes("ECONNRESET") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("socket hang up");
|
|
14680
|
-
if (isRateLimited || isTransientError) {
|
|
14681
|
-
const retryAfterSeconds = Math.min(120, Math.pow(2, attempt) * 2);
|
|
14682
|
-
const reason = isRateLimited ? "Rate limit exceeded (429)" : `Transient server error (${status || "network"})`;
|
|
14683
|
-
throw new RetryableError(`[${options.stepName}] ${reason}. Retrying attempt ${attempt + 1}...`, {
|
|
14684
|
-
retryAfter: `${retryAfterSeconds}s`
|
|
14685
|
-
});
|
|
14686
|
-
}
|
|
14687
|
-
throw error;
|
|
14688
|
-
}
|
|
14689
|
-
}
|
|
14690
14663
|
|
|
14691
|
-
// src/
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
|
|
14706
|
-
|
|
14664
|
+
// src/index.ts
|
|
14665
|
+
init_errors();
|
|
14666
|
+
|
|
14667
|
+
// src/evaluators/deterministicStructuralLinter.ts
|
|
14668
|
+
var DeterministicStructuralLinter = class {
|
|
14669
|
+
/**
|
|
14670
|
+
* Validates structural invariants across a complete lesson bundle.
|
|
14671
|
+
*/
|
|
14672
|
+
static lintBundle(input) {
|
|
14673
|
+
const { lesson, quiz, activity, slides, codeLab } = input;
|
|
14674
|
+
const findings = [];
|
|
14675
|
+
const strengths = [];
|
|
14676
|
+
let score = 100;
|
|
14677
|
+
const baseLessonId = lesson.lessonId;
|
|
14678
|
+
const baseLanguage = lesson.language;
|
|
14679
|
+
if (!lesson.title || lesson.title.trim().length === 0) {
|
|
14680
|
+
score -= 20;
|
|
14681
|
+
findings.push({
|
|
14682
|
+
id: "struct_missing_lesson_title",
|
|
14683
|
+
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
14684
|
+
severity: "CRITICAL",
|
|
14685
|
+
title: "Missing Lesson Title",
|
|
14686
|
+
description: "Lesson plan has an empty or whitespace title.",
|
|
14687
|
+
remediationAdvice: "Provide a non-empty lesson title."
|
|
14707
14688
|
});
|
|
14708
14689
|
}
|
|
14709
|
-
|
|
14710
|
-
|
|
14711
|
-
|
|
14712
|
-
|
|
14713
|
-
|
|
14714
|
-
|
|
14715
|
-
|
|
14716
|
-
|
|
14717
|
-
|
|
14718
|
-
stepName: `judge-master-lesson-${input.lessonId}`,
|
|
14719
|
-
fn: async () => {
|
|
14720
|
-
return auditCurriculumQualityFlow({
|
|
14721
|
-
targetArtifactType: "LESSON",
|
|
14722
|
-
lessonId: input.lessonId,
|
|
14723
|
-
expectedLanguage: input.language,
|
|
14724
|
-
targetObjectives: input.targetObjectives,
|
|
14725
|
-
generatedContentJson: JSON.stringify(input.lesson, null, 2),
|
|
14726
|
-
standardStatements: input.standardStatements,
|
|
14727
|
-
modelOptions: input.modelOptions
|
|
14690
|
+
if (!lesson.learningObjectives || lesson.learningObjectives.length === 0) {
|
|
14691
|
+
score -= 25;
|
|
14692
|
+
findings.push({
|
|
14693
|
+
id: "struct_empty_learning_objectives",
|
|
14694
|
+
dimension: "CONSTRUCTIVE_ALIGNMENT",
|
|
14695
|
+
severity: "CRITICAL",
|
|
14696
|
+
title: "Empty Learning Objectives Array",
|
|
14697
|
+
description: "Lesson plan contains 0 learning objectives.",
|
|
14698
|
+
remediationAdvice: "Declare at least 2 structured Learning Objectives in the schema."
|
|
14728
14699
|
});
|
|
14729
14700
|
}
|
|
14730
|
-
|
|
14731
|
-
|
|
14732
|
-
|
|
14733
|
-
|
|
14734
|
-
|
|
14735
|
-
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14739
|
-
Detected Issues:
|
|
14740
|
-
${input.auditReport.criteria.filter((c) => !c.passed).map((c) => `- [${c.name}] ${c.feedback}`).join("\n")}
|
|
14741
|
-
Actionable Repairs:
|
|
14742
|
-
${input.auditReport.actionableRepairPrompts.map((p) => `* ${p}`).join("\n")}
|
|
14743
|
-
Language Adherence Required: "${input.language}"
|
|
14744
|
-
`.trim();
|
|
14745
|
-
return withRateLimitBackoff({
|
|
14746
|
-
stepName: `repair-master-lesson-${input.milestone.id || "L01"}`,
|
|
14747
|
-
fn: async () => {
|
|
14748
|
-
return generateLessonMasterFlow({
|
|
14749
|
-
milestone: input.milestone,
|
|
14750
|
-
language: input.language,
|
|
14751
|
-
topic: input.topic,
|
|
14752
|
-
targetAudience: input.targetAudience,
|
|
14753
|
-
contextContinuity: repairFeedback,
|
|
14754
|
-
standardsContext: input.standardsContext,
|
|
14755
|
-
modelOptions: input.modelOptions
|
|
14701
|
+
if (!lesson.sections || lesson.sections.length === 0) {
|
|
14702
|
+
score -= 25;
|
|
14703
|
+
findings.push({
|
|
14704
|
+
id: "struct_empty_lesson_sections",
|
|
14705
|
+
dimension: "5E_INSTRUCTIONAL_FIDELITY",
|
|
14706
|
+
severity: "CRITICAL",
|
|
14707
|
+
title: "Empty Lesson Sections Array",
|
|
14708
|
+
description: "Lesson plan contains no instructional sections.",
|
|
14709
|
+
remediationAdvice: "Provide structured lesson flow sections."
|
|
14756
14710
|
});
|
|
14757
14711
|
}
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
fn: async () => generateActivityFlow(options)
|
|
14769
|
-
});
|
|
14770
|
-
console.log(` \u2705 [Step: Activity Lab] Done in ${((Date.now() - t0) / 1e3).toFixed(1)}s (Title: "${res.title}")`);
|
|
14771
|
-
return res;
|
|
14772
|
-
}
|
|
14773
|
-
async function generateCodeLabStep(options) {
|
|
14774
|
-
"use step";
|
|
14775
|
-
console.log(` \u23F3 [Step: Code Lab] Generating starter & solution code LAB.md...`);
|
|
14776
|
-
const t0 = Date.now();
|
|
14777
|
-
const res = await withRateLimitBackoff({
|
|
14778
|
-
stepName: `generate-lab-${options.lesson.lessonId}`,
|
|
14779
|
-
fn: async () => generateCodeLabFlow(options)
|
|
14780
|
-
});
|
|
14781
|
-
console.log(` \u2705 [Step: Code Lab] Done in ${((Date.now() - t0) / 1e3).toFixed(1)}s (Title: "${res.title}")`);
|
|
14782
|
-
return res;
|
|
14783
|
-
}
|
|
14784
|
-
async function generateSelfLabStep(options) {
|
|
14785
|
-
"use step";
|
|
14786
|
-
console.log(` \u23F3 [Step: Self-Lab] Generating SELF_LAB.md with Progressive Hints...`);
|
|
14787
|
-
const t0 = Date.now();
|
|
14788
|
-
const res = await withRateLimitBackoff({
|
|
14789
|
-
stepName: `generate-self-lab-${options.milestone.id || "L01"}`,
|
|
14790
|
-
fn: async () => generateSelfLabFlow(options)
|
|
14791
|
-
});
|
|
14792
|
-
console.log(` \u2705 [Step: Self-Lab] Done in ${((Date.now() - t0) / 1e3).toFixed(1)}s (Challenges: 3 tiers Bronze/Silver/Gold)`);
|
|
14793
|
-
return res;
|
|
14794
|
-
}
|
|
14795
|
-
async function generateDiagnosticQuizStep(options) {
|
|
14796
|
-
"use step";
|
|
14797
|
-
console.log(` \u23F3 [Step: Diagnostic Quiz] Generating QUIZ.json Bloom Assessment...`);
|
|
14798
|
-
const t0 = Date.now();
|
|
14799
|
-
const res = await withRateLimitBackoff({
|
|
14800
|
-
stepName: `generate-quiz-${options.milestone.id || "L01"}`,
|
|
14801
|
-
fn: async () => generateDiagnosticQuizFlow(options)
|
|
14802
|
-
});
|
|
14803
|
-
console.log(` \u2705 [Step: Diagnostic Quiz] Done in ${((Date.now() - t0) / 1e3).toFixed(1)}s (Questions: ${res.questions.length})`);
|
|
14804
|
-
return res;
|
|
14805
|
-
}
|
|
14806
|
-
async function generateSlidesStep(options) {
|
|
14807
|
-
"use step";
|
|
14808
|
-
console.log(` \u23F3 [Step: Slides] Generating Marp presentation SLIDE.md...`);
|
|
14809
|
-
const t0 = Date.now();
|
|
14810
|
-
const res = await withRateLimitBackoff({
|
|
14811
|
-
stepName: `generate-slides-${options.lesson.lessonId}`,
|
|
14812
|
-
fn: async () => generateSlidesFlow(options)
|
|
14813
|
-
});
|
|
14814
|
-
console.log(` \u2705 [Step: Slides] Done in ${((Date.now() - t0) / 1e3).toFixed(1)}s (Slides: ${res.slides.length})`);
|
|
14815
|
-
return res;
|
|
14816
|
-
}
|
|
14817
|
-
async function generateHandoutStep(options) {
|
|
14818
|
-
"use step";
|
|
14819
|
-
console.log(` \u23F3 [Step: Handout] Generating 5-Second Rule HANDOUT.md...`);
|
|
14820
|
-
const t0 = Date.now();
|
|
14821
|
-
const res = await withRateLimitBackoff({
|
|
14822
|
-
stepName: `generate-handout-${options.lesson.lessonId}`,
|
|
14823
|
-
fn: async () => generateHandoutFlow(options)
|
|
14824
|
-
});
|
|
14825
|
-
console.log(` \u2705 [Step: Handout] Done in ${((Date.now() - t0) / 1e3).toFixed(1)}s (Title: "${res.title}")`);
|
|
14826
|
-
return res;
|
|
14827
|
-
}
|
|
14828
|
-
async function generateWorksheetStep(options) {
|
|
14829
|
-
"use step";
|
|
14830
|
-
return withRateLimitBackoff({
|
|
14831
|
-
stepName: `generate-worksheet-${options.lesson.lessonId}`,
|
|
14832
|
-
fn: async () => generateWorksheetFlow(options)
|
|
14833
|
-
});
|
|
14834
|
-
}
|
|
14835
|
-
async function generateTeacherGuideStep(options) {
|
|
14836
|
-
"use step";
|
|
14837
|
-
return withRateLimitBackoff({
|
|
14838
|
-
stepName: `generate-teacher-guide-${options.lesson.lessonId}`,
|
|
14839
|
-
fn: async () => generateTeacherGuideFlow(options)
|
|
14840
|
-
});
|
|
14841
|
-
}
|
|
14842
|
-
async function generateExtensionStep(options) {
|
|
14843
|
-
"use step";
|
|
14844
|
-
return withRateLimitBackoff({
|
|
14845
|
-
stepName: `generate-extension-${options.lesson.lessonId}`,
|
|
14846
|
-
fn: async () => generateExtensionFlow(options)
|
|
14847
|
-
});
|
|
14848
|
-
}
|
|
14849
|
-
|
|
14850
|
-
// src/workflow/steps/satelliteJudgeStep.ts
|
|
14851
|
-
async function judgeSatelliteStep(input) {
|
|
14852
|
-
"use step";
|
|
14853
|
-
const t0 = Date.now();
|
|
14854
|
-
console.log(" \u{1F9D1}\u200D\u2696\uFE0F [Step: Satellite Judge] " + input.artifactType + " (" + input.artifactId + ")...");
|
|
14855
|
-
return withRateLimitBackoff({
|
|
14856
|
-
stepName: "judge-satellite-" + input.artifactType + "-" + input.artifactId,
|
|
14857
|
-
fn: async () => {
|
|
14858
|
-
return auditCurriculumQualityFlow({
|
|
14859
|
-
targetArtifactType: input.artifactType,
|
|
14860
|
-
lessonId: input.artifactId,
|
|
14861
|
-
expectedLanguage: input.language,
|
|
14862
|
-
targetObjectives: input.targetObjectives,
|
|
14863
|
-
generatedContentJson: JSON.stringify(input.artifact),
|
|
14864
|
-
standardStatements: input.standardStatements,
|
|
14865
|
-
modelOptions: input.modelOptions
|
|
14712
|
+
if (quiz && quiz.quizId !== baseLessonId && !quiz.quizId.includes(baseLessonId)) {
|
|
14713
|
+
score -= 15;
|
|
14714
|
+
findings.push({
|
|
14715
|
+
id: "struct_quiz_id_mismatch",
|
|
14716
|
+
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
14717
|
+
severity: "MAJOR",
|
|
14718
|
+
title: "Quiz ID Contract Mismatch",
|
|
14719
|
+
description: `Quiz ID "${quiz.quizId}" does not match Lesson ID "${baseLessonId}".`,
|
|
14720
|
+
remediationAdvice: `Sync Quiz quizId to "${baseLessonId}".`,
|
|
14721
|
+
affectedElement: quiz.quizId
|
|
14866
14722
|
});
|
|
14867
14723
|
}
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
const lessonMd = serializeLessonToMarkdown(input.lesson);
|
|
14880
|
-
const p1 = await manager.saveArtifact(input.jobId, input.milestoneSlug, "LESSON_5E.md", lessonMd, "LESSON");
|
|
14881
|
-
savedFiles.push(p1);
|
|
14882
|
-
if (input.activity) {
|
|
14883
|
-
const actMd = serializeActivityToMarkdown(input.activity);
|
|
14884
|
-
const p2 = await manager.saveArtifact(input.jobId, input.milestoneSlug, "ACT.md", actMd, "ACT");
|
|
14885
|
-
savedFiles.push(p2);
|
|
14886
|
-
}
|
|
14887
|
-
if (input.codeLab) {
|
|
14888
|
-
const labContent = serializeCodeLabToMarkdown(input.codeLab);
|
|
14889
|
-
const p3 = await manager.saveArtifact(input.jobId, input.milestoneSlug, "LAB.md", labContent, "LAB");
|
|
14890
|
-
savedFiles.push(p3);
|
|
14891
|
-
}
|
|
14892
|
-
if (input.selfLab) {
|
|
14893
|
-
const selfLabMd = serializeSelfLabToMarkdown(input.selfLab);
|
|
14894
|
-
const p4 = await manager.saveArtifact(input.jobId, input.milestoneSlug, "SELF_LAB.md", selfLabMd, "SELF_LAB");
|
|
14895
|
-
savedFiles.push(p4);
|
|
14896
|
-
}
|
|
14897
|
-
if (input.quiz) {
|
|
14898
|
-
const quizMd = serializeDiagnosticQuizToMarkdown(input.quiz);
|
|
14899
|
-
const p5a = await manager.saveArtifact(input.jobId, input.milestoneSlug, "QUIZ.md", quizMd, "QUIZ_MD");
|
|
14900
|
-
const p5b = await manager.saveArtifact(
|
|
14901
|
-
input.jobId,
|
|
14902
|
-
input.milestoneSlug,
|
|
14903
|
-
"QUIZ.json",
|
|
14904
|
-
JSON.stringify(input.quiz, null, 2),
|
|
14905
|
-
"QUIZ_JSON"
|
|
14906
|
-
);
|
|
14907
|
-
savedFiles.push(p5a, p5b);
|
|
14908
|
-
}
|
|
14909
|
-
if (input.slides) {
|
|
14910
|
-
const slidesContent = `---
|
|
14911
|
-
marp: true
|
|
14912
|
-
theme: default
|
|
14913
|
-
paginate: true
|
|
14914
|
-
---
|
|
14915
|
-
|
|
14916
|
-
# ${input.slides.title}
|
|
14917
|
-
|
|
14918
|
-
---
|
|
14919
|
-
|
|
14920
|
-
${input.slides.slides.map((s) => `## Slide ${s.slideNumber}: ${s.title}
|
|
14921
|
-
|
|
14922
|
-
${s.bulletPoints.map((b) => `- ${b}`).join("\n")}${s.codeSnippet ? `
|
|
14923
|
-
|
|
14924
|
-
\`\`\`
|
|
14925
|
-
${s.codeSnippet}
|
|
14926
|
-
\`\`\`` : ""}
|
|
14927
|
-
|
|
14928
|
-
<!-- Presenter Notes: ${s.presenterNotes || ""} -->`).join("\n\n---\n\n")}
|
|
14929
|
-
`.trim();
|
|
14930
|
-
const p6 = await manager.saveArtifact(input.jobId, input.milestoneSlug, "SLIDE.md", slidesContent, "SLIDES");
|
|
14931
|
-
savedFiles.push(p6);
|
|
14932
|
-
}
|
|
14933
|
-
if (input.handout) {
|
|
14934
|
-
const handoutMd = serializeHandoutToMarkdown(input.handout);
|
|
14935
|
-
const p7 = await manager.saveArtifact(input.jobId, input.milestoneSlug, "HANDOUT.md", handoutMd, "HANDOUT");
|
|
14936
|
-
savedFiles.push(p7);
|
|
14937
|
-
}
|
|
14938
|
-
if (input.cheatSheetMarkdown) {
|
|
14939
|
-
const p8 = await manager.saveArtifact(
|
|
14940
|
-
input.jobId,
|
|
14941
|
-
input.milestoneSlug,
|
|
14942
|
-
"CHEAT_SHEET.md",
|
|
14943
|
-
input.cheatSheetMarkdown,
|
|
14944
|
-
"CHEAT_SHEET"
|
|
14945
|
-
);
|
|
14946
|
-
savedFiles.push(p8);
|
|
14947
|
-
}
|
|
14948
|
-
await manager.markMilestoneCompleted(input.jobId);
|
|
14949
|
-
return {
|
|
14950
|
-
milestoneSlug: input.milestoneSlug,
|
|
14951
|
-
savedFiles
|
|
14952
|
-
};
|
|
14953
|
-
}
|
|
14954
|
-
async function publishToGitStep(options) {
|
|
14955
|
-
"use step";
|
|
14956
|
-
return publishToGitHub(options);
|
|
14957
|
-
}
|
|
14958
|
-
async function publishToSupabaseStep(options) {
|
|
14959
|
-
"use step";
|
|
14960
|
-
return publishToSupabase(options);
|
|
14961
|
-
}
|
|
14962
|
-
var approvalPayloadSchema = z.object({
|
|
14963
|
-
approved: z.boolean().describe("Whether the human reviewer approves the generated curriculum/lesson"),
|
|
14964
|
-
reviewerName: z.string().optional().describe("Name or ID of the reviewer"),
|
|
14965
|
-
feedback: z.string().optional().describe("Actionable feedback or required changes if rejected"),
|
|
14966
|
-
timestamp: z.string().optional().describe("ISO timestamp of the approval action")
|
|
14967
|
-
});
|
|
14968
|
-
var lessonApprovalHook = defineHook();
|
|
14969
|
-
function approvalHookToken(projectId, lessonId, artifactType) {
|
|
14970
|
-
return `approval:${projectId}:${lessonId}:${artifactType}`;
|
|
14971
|
-
}
|
|
14972
|
-
|
|
14973
|
-
// src/standards/standardsCoverageGate.ts
|
|
14974
|
-
function resolveStatementRef(ref, packs) {
|
|
14975
|
-
const [head, ...rest] = ref.split(":");
|
|
14976
|
-
const candidatePacks = rest.length > 0 ? packs.filter((p) => p.manifest.id === head) : packs;
|
|
14977
|
-
const statementId = rest.length > 0 ? rest.join(":") : ref;
|
|
14978
|
-
for (const p of candidatePacks) {
|
|
14979
|
-
if (p.statements.some((s) => s.id === statementId)) return { pack: p, statementId };
|
|
14980
|
-
}
|
|
14981
|
-
return null;
|
|
14982
|
-
}
|
|
14983
|
-
function evaluateStandardsCoverage(input) {
|
|
14984
|
-
const rows = [];
|
|
14985
|
-
const aoToLo = /* @__PURE__ */ new Map();
|
|
14986
|
-
for (const ao of input.assessmentObjectives ?? []) aoToLo.set(ao.aoCode, ao.alignedLO);
|
|
14987
|
-
const loToRefs = /* @__PURE__ */ new Map();
|
|
14988
|
-
for (const lo of input.objectives) {
|
|
14989
|
-
loToRefs.set(lo.code, new Set(lo.standardRefs ?? []));
|
|
14990
|
-
}
|
|
14991
|
-
const taughtLOs = /* @__PURE__ */ new Set();
|
|
14992
|
-
for (const act of input.activities ?? []) for (const lo of act.lo) taughtLOs.add(lo);
|
|
14993
|
-
const assessedLOs = /* @__PURE__ */ new Set();
|
|
14994
|
-
for (const q of input.quizQuestions) {
|
|
14995
|
-
if (q.alignedLO) assessedLOs.add(q.alignedLO);
|
|
14996
|
-
if (q.alignedAO) {
|
|
14997
|
-
const lo = aoToLo.get(q.alignedAO);
|
|
14998
|
-
if (lo) assessedLOs.add(lo);
|
|
14999
|
-
}
|
|
15000
|
-
}
|
|
15001
|
-
for (const pack of input.packs) {
|
|
15002
|
-
const mappingByStatement = /* @__PURE__ */ new Map();
|
|
15003
|
-
for (const m of pack.mappings ?? []) {
|
|
15004
|
-
const prev = mappingByStatement.get(m.statementId);
|
|
15005
|
-
if (!prev || prev !== "covers" && m.kind === "covers" || prev === "extends" && m.kind !== "extends") {
|
|
15006
|
-
mappingByStatement.set(m.statementId, m.kind);
|
|
15007
|
-
}
|
|
14724
|
+
if (activity && activity.lessonId !== baseLessonId) {
|
|
14725
|
+
score -= 15;
|
|
14726
|
+
findings.push({
|
|
14727
|
+
id: "struct_act_id_mismatch",
|
|
14728
|
+
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
14729
|
+
severity: "MAJOR",
|
|
14730
|
+
title: "Activity Lesson ID Contract Mismatch",
|
|
14731
|
+
description: `Activity lessonId "${activity.lessonId}" does not match Lesson ID "${baseLessonId}".`,
|
|
14732
|
+
remediationAdvice: `Sync Activity lessonId to "${baseLessonId}".`,
|
|
14733
|
+
affectedElement: activity.lessonId
|
|
14734
|
+
});
|
|
15008
14735
|
}
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
if (!hasMapping) status = "UNMAPPED";
|
|
15020
|
-
else if (!isComplianceRelevant) status = "PARTIAL";
|
|
15021
|
-
else if (los.length > 0 && hasActivity && hasAssessment) status = "COVERED";
|
|
15022
|
-
else status = "UNCOVERED";
|
|
15023
|
-
if (status === "UNCOVERED") {
|
|
15024
|
-
if (los.length === 0) issues.push("No learning objective anchors this statement (missing standardRefs).");
|
|
15025
|
-
else {
|
|
15026
|
-
if (!hasActivity) issues.push(`Anchored LO(s) ${los.join(", ")} have no activity in lesson flow.`);
|
|
15027
|
-
if (!hasAssessment) issues.push(`Anchored LO(s) ${los.join(", ")} are not measured by any quiz question.`);
|
|
15028
|
-
}
|
|
15029
|
-
}
|
|
15030
|
-
rows.push({
|
|
15031
|
-
packId: pack.manifest.id,
|
|
15032
|
-
statementId: statement.id,
|
|
15033
|
-
statementText: Object.values(statement.texts)[0] ?? "",
|
|
15034
|
-
status,
|
|
15035
|
-
objectives: los,
|
|
15036
|
-
hasActivity,
|
|
15037
|
-
hasAssessment,
|
|
15038
|
-
issues
|
|
14736
|
+
if (slides && slides.lessonId !== baseLessonId) {
|
|
14737
|
+
score -= 15;
|
|
14738
|
+
findings.push({
|
|
14739
|
+
id: "struct_slides_id_mismatch",
|
|
14740
|
+
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
14741
|
+
severity: "MAJOR",
|
|
14742
|
+
title: "Slide Deck Lesson ID Contract Mismatch",
|
|
14743
|
+
description: `Slide deck lessonId "${slides.lessonId}" does not match Lesson ID "${baseLessonId}".`,
|
|
14744
|
+
remediationAdvice: `Sync Slide deck lessonId to "${baseLessonId}".`,
|
|
14745
|
+
affectedElement: slides.lessonId
|
|
15039
14746
|
});
|
|
15040
14747
|
}
|
|
15041
|
-
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
14748
|
+
const satellites = [
|
|
14749
|
+
{ type: "QUIZ", lang: quiz?.language },
|
|
14750
|
+
{ type: "ACT", lang: activity?.language },
|
|
14751
|
+
{ type: "SLIDE", lang: slides?.language }
|
|
14752
|
+
];
|
|
14753
|
+
for (const sat of satellites) {
|
|
14754
|
+
if (sat.lang && sat.lang.toLowerCase() !== baseLanguage.toLowerCase()) {
|
|
14755
|
+
score -= 25;
|
|
14756
|
+
findings.push({
|
|
14757
|
+
id: `struct_language_mismatch_${sat.type}`,
|
|
14758
|
+
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
14759
|
+
severity: "CRITICAL",
|
|
14760
|
+
title: `Language Policy Inconsistency in ${sat.type}`,
|
|
14761
|
+
description: `Master Lesson is in "${baseLanguage}" but ${sat.type} is declared in "${sat.lang}".`,
|
|
14762
|
+
remediationAdvice: `Set ${sat.type} language to "${baseLanguage}".`
|
|
15054
14763
|
});
|
|
15055
14764
|
}
|
|
15056
14765
|
}
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
-
|
|
15070
|
-
|
|
15071
|
-
|
|
15072
|
-
|
|
15073
|
-
|
|
15074
|
-
|
|
15075
|
-
|
|
15076
|
-
|
|
15077
|
-
|
|
15078
|
-
|
|
15079
|
-
|
|
15080
|
-
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
|
|
15084
|
-
|
|
15085
|
-
}
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
constructor(config = {}) {
|
|
15089
|
-
if (config.client) {
|
|
15090
|
-
this.client = config.client;
|
|
15091
|
-
return;
|
|
15092
|
-
}
|
|
15093
|
-
const url = config.supabaseUrl || process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.SUPABASE_URL || "";
|
|
15094
|
-
const key = config.supabaseServiceRoleKey || process.env.SUPABASE_SERVICE_ROLE_KEY || config.supabaseAnonKey || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "";
|
|
15095
|
-
if (!url || !key) {
|
|
15096
|
-
throw new Error("StandardsRegistryAdapter: Supabase URL/key missing (pass client or env).");
|
|
14766
|
+
if (quiz && quiz.questions) {
|
|
14767
|
+
for (let i = 0; i < quiz.questions.length; i++) {
|
|
14768
|
+
const q = quiz.questions[i];
|
|
14769
|
+
const qId = q.id || `Q${i + 1}`;
|
|
14770
|
+
const options = q.options || [];
|
|
14771
|
+
if (options.length < 4) {
|
|
14772
|
+
score -= 10;
|
|
14773
|
+
findings.push({
|
|
14774
|
+
id: `struct_quiz_option_count_${qId}`,
|
|
14775
|
+
dimension: "MISCONCEPTION_RIGOR",
|
|
14776
|
+
severity: "MAJOR",
|
|
14777
|
+
title: `Structural Option Count Error in ${qId}`,
|
|
14778
|
+
description: `Question ${qId} has ${options.length} options (standard schema requires 4).`,
|
|
14779
|
+
remediationAdvice: "Ensure each question has 4 options (A, B, C, D).",
|
|
14780
|
+
affectedElement: qId
|
|
14781
|
+
});
|
|
14782
|
+
}
|
|
14783
|
+
const correctCount = options.filter((o) => o.isCorrect).length;
|
|
14784
|
+
if (correctCount !== 1) {
|
|
14785
|
+
score -= 20;
|
|
14786
|
+
findings.push({
|
|
14787
|
+
id: `struct_quiz_key_count_${qId}`,
|
|
14788
|
+
dimension: "MISCONCEPTION_RIGOR",
|
|
14789
|
+
severity: "CRITICAL",
|
|
14790
|
+
title: `Key Assignment Error in ${qId}`,
|
|
14791
|
+
description: `Question ${qId} has ${correctCount} correct options (must be exactly 1).`,
|
|
14792
|
+
remediationAdvice: "Set `isCorrect: true` on exactly 1 option.",
|
|
14793
|
+
affectedElement: qId
|
|
14794
|
+
});
|
|
14795
|
+
}
|
|
14796
|
+
}
|
|
15097
14797
|
}
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
14798
|
+
if (activity?.materialsBOM?.hardware && activity.materialsBOM.hardware.length > 0) {
|
|
14799
|
+
const hwText = activity.materialsBOM.hardware.join(" ").toLowerCase();
|
|
14800
|
+
const hasLED = hwText.includes("led");
|
|
14801
|
+
const hasResistor = hwText.includes("\u0111i\u1EC7n tr\u1EDF") || hwText.includes("resistor") || hwText.includes("220") || hwText.includes("330") || hwText.includes("1k");
|
|
14802
|
+
if (hasLED && !hasResistor) {
|
|
14803
|
+
score -= 20;
|
|
14804
|
+
findings.push({
|
|
14805
|
+
id: "struct_hardware_unsafe_led_no_resistor",
|
|
14806
|
+
dimension: "TECHNICAL_AUTHENTICITY",
|
|
14807
|
+
severity: "CRITICAL",
|
|
14808
|
+
title: "Unsafe Circuit BOM: LED without Current-Limiting Resistor",
|
|
14809
|
+
description: "Hardware BOM includes LED without a 220\u03A9-1k\u03A9 resistor, causing circuit overload.",
|
|
14810
|
+
remediationAdvice: "Add a 220\u03A9 current-limiting resistor to the hardware materials list."
|
|
14811
|
+
});
|
|
14812
|
+
}
|
|
15106
14813
|
}
|
|
15107
|
-
|
|
15108
|
-
const
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
name: p.manifest.name,
|
|
15112
|
-
spec_version: p.manifest.specVersion,
|
|
15113
|
-
subject: p.manifest.subject,
|
|
15114
|
-
languages: p.manifest.languages,
|
|
15115
|
-
grade_model: p.manifest.gradeModel,
|
|
15116
|
-
provenance: p.manifest.provenance,
|
|
15117
|
-
trust: p.manifest.trust,
|
|
15118
|
-
status: "draft",
|
|
15119
|
-
organization_code: opts?.organizationCode ?? (p.manifest.trust === "verified" ? null : p.manifest.provenance.importedBy?.replace(/^org:/, "") || null),
|
|
15120
|
-
original_file_path: opts?.originalFilePath ?? null,
|
|
15121
|
-
created_by: opts?.createdBy ?? null
|
|
15122
|
-
}).select("id").single();
|
|
15123
|
-
if (fwErr) throw new Error("importPack: framework insert failed: " + fwErr.message);
|
|
15124
|
-
const frameworkId = fw.id;
|
|
15125
|
-
const statementRows = p.statements.map((s) => ({
|
|
15126
|
-
framework_id: frameworkId,
|
|
15127
|
-
statement_id: s.id,
|
|
15128
|
-
parent_statement_id: s.parentId ?? null,
|
|
15129
|
-
grade_min: s.gradeBand[0],
|
|
15130
|
-
grade_max: s.gradeBand[1],
|
|
15131
|
-
texts: s.texts,
|
|
15132
|
-
classifications: s.classifications ?? [],
|
|
15133
|
-
bloom_hint: s.bloomHint ?? null,
|
|
15134
|
-
keywords: s.keywords ?? [],
|
|
15135
|
-
source_ref: s.sourceRef ?? null,
|
|
15136
|
-
provenance: s.provenance
|
|
15137
|
-
}));
|
|
15138
|
-
const { error: stErr, count: stCount } = await this.client.from("standards_statements").insert(statementRows, { count: "exact" });
|
|
15139
|
-
if (stErr) throw new Error("importPack: statement insert failed: " + stErr.message);
|
|
15140
|
-
let mappingCount = 0;
|
|
15141
|
-
if (p.mappings && p.mappings.length > 0) {
|
|
15142
|
-
const mappingRows = p.mappings.map((m) => ({
|
|
15143
|
-
framework_id: frameworkId,
|
|
15144
|
-
statement_id: m.statementId,
|
|
15145
|
-
target_ref: m.targetRef,
|
|
15146
|
-
kind: m.kind,
|
|
15147
|
-
confidence: m.confidence,
|
|
15148
|
-
provenance: m.provenance
|
|
15149
|
-
}));
|
|
15150
|
-
const { error: mpErr, count: mpCount } = await this.client.from("standards_mappings").insert(mappingRows, { count: "exact" });
|
|
15151
|
-
if (mpErr) throw new Error("importPack: mapping insert failed: " + mpErr.message);
|
|
15152
|
-
mappingCount = mpCount ?? mappingRows.length;
|
|
14814
|
+
score = Math.max(0, Math.min(100, score));
|
|
14815
|
+
const passed = score >= 80 && !findings.some((f) => f.severity === "CRITICAL");
|
|
14816
|
+
if (passed) {
|
|
14817
|
+
strengths.push("Deterministic structure, ID contracts, and schema invariants strictly verified.");
|
|
15153
14818
|
}
|
|
15154
|
-
return {
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15160
|
-
}
|
|
15161
|
-
async deprecatePack(frameworkDbId) {
|
|
15162
|
-
const { error } = await this.client.from("standards_frameworks").update({ status: "deprecated" }).eq("id", frameworkDbId);
|
|
15163
|
-
if (error) throw new Error("deprecatePack failed: " + error.message);
|
|
15164
|
-
}
|
|
15165
|
-
async adoptPack(frameworkDbId, organizationCode, adoptedBy) {
|
|
15166
|
-
const { error } = await this.client.from("standards_org_adoptions").upsert(
|
|
15167
|
-
{ framework_id: frameworkDbId, organization_code: organizationCode, adopted_by: adoptedBy ?? null },
|
|
15168
|
-
{ onConflict: "organization_code,framework_id" }
|
|
15169
|
-
);
|
|
15170
|
-
if (error) throw new Error("adoptPack failed: " + error.message);
|
|
14819
|
+
return {
|
|
14820
|
+
passed,
|
|
14821
|
+
structuralScore: score,
|
|
14822
|
+
findings,
|
|
14823
|
+
strengths
|
|
14824
|
+
};
|
|
15171
14825
|
}
|
|
15172
|
-
|
|
14826
|
+
};
|
|
14827
|
+
|
|
14828
|
+
// src/evaluators/academicAuditor.ts
|
|
14829
|
+
var AcademicAuditor = class {
|
|
15173
14830
|
/**
|
|
15174
|
-
*
|
|
15175
|
-
*
|
|
15176
|
-
*
|
|
14831
|
+
* Evaluates a complete lesson bundle.
|
|
14832
|
+
* Step 1 (Deterministic): Fast structural, contract, schema, and safety linting.
|
|
14833
|
+
* Step 2 (Semantic LLM-as-a-Judge): Deep pedagogical, cognitive (Bloom), and misconception analysis with live frontier LLM.
|
|
15177
14834
|
*/
|
|
15178
|
-
async
|
|
15179
|
-
|
|
15180
|
-
const
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
return global || own || adopted;
|
|
14835
|
+
static async auditLessonBundle(input) {
|
|
14836
|
+
const { lesson, quiz, activity, slides, codeLab, modelOptions, executeLLMJudge = true } = input;
|
|
14837
|
+
const structuralResult = DeterministicStructuralLinter.lintBundle({
|
|
14838
|
+
lesson,
|
|
14839
|
+
quiz,
|
|
14840
|
+
activity,
|
|
14841
|
+
slides,
|
|
14842
|
+
codeLab
|
|
15187
14843
|
});
|
|
15188
|
-
|
|
15189
|
-
const
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
|
|
15196
|
-
|
|
15197
|
-
|
|
15198
|
-
|
|
15199
|
-
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15222
|
-
})
|
|
15223
|
-
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
|
|
15234
|
-
const hydrated = FrameworkPackSchema.safeParse({
|
|
15235
|
-
manifest: {
|
|
15236
|
-
id: f.pack_id,
|
|
15237
|
-
name: f.name,
|
|
15238
|
-
specVersion: f.spec_version || "1.0",
|
|
15239
|
-
contentVersion: f.content_version,
|
|
15240
|
-
subject: f.subject,
|
|
15241
|
-
languages: f.languages,
|
|
15242
|
-
gradeModel: f.grade_model,
|
|
15243
|
-
provenance: f.provenance,
|
|
15244
|
-
trust: f.trust
|
|
15245
|
-
},
|
|
15246
|
-
statements: stmts,
|
|
15247
|
-
mappings: finalMappings
|
|
15248
|
-
});
|
|
15249
|
-
if (!hydrated.success) {
|
|
15250
|
-
throw new Error('loadPacksForOrg: hydrated pack "' + f.pack_id + '" failed schema: ' + hydrated.error.issues[0]?.message);
|
|
15251
|
-
}
|
|
15252
|
-
return { ...hydrated.data, dbId: f.id, status: f.status, organizationCode: f.organization_code ?? null };
|
|
15253
|
-
});
|
|
15254
|
-
}
|
|
15255
|
-
};
|
|
15256
|
-
|
|
15257
|
-
// src/workflow/workflows/milestoneWorkflow.ts
|
|
15258
|
-
async function generateMilestoneWorkflow(input) {
|
|
15259
|
-
"use workflow";
|
|
15260
|
-
const language = input.language || "vi";
|
|
15261
|
-
const milestoneId = input.milestone.id || input.milestone.concept_code || "L01";
|
|
15262
|
-
const slugPrefix = /^\d+$/.test(milestoneId) ? `M${milestoneId.padStart(2, "0")}` : milestoneId;
|
|
15263
|
-
const milestoneSlug = `${slugPrefix}_${(input.milestone.name || "milestone").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "")}`;
|
|
15264
|
-
const bundleTier = input.bundleTier || "minimum";
|
|
15265
|
-
const gates = resolveGateSettings(input.gateSettings);
|
|
15266
|
-
const techStack = input.techStack || input.milestone.tech_keywords || ["General Technology"];
|
|
15267
|
-
console.log(" \u{1F6A6} [Gate] LESSON: " + gates.LESSON + " | ACT: " + gates.ACT + " | QUIZ: " + gates.QUIZ);
|
|
15268
|
-
const targetObjectives = (input.milestone.learning_objectives || []).map((lo) => ({
|
|
15269
|
-
code: lo.code,
|
|
15270
|
-
description: lo.description || lo.name || "",
|
|
15271
|
-
bloomLevel: lo.bloom_level || "understand"
|
|
15272
|
-
}));
|
|
15273
|
-
const packs = input.standardsPacks ?? [];
|
|
15274
|
-
const { block: standardsContext, selected: selectedStatements } = buildStandardsContext({
|
|
15275
|
-
packs,
|
|
15276
|
-
gradeBand: input.milestone.grade_band ?? [6, 12],
|
|
15277
|
-
topicText: [input.topic, input.milestone.name, input.milestone.description, ...input.milestone.tech_keywords || []].filter(Boolean).join(" "),
|
|
15278
|
-
conceptCodes: (input.milestone.concept_code || "").split(",").map((c) => c.trim()).filter(Boolean),
|
|
15279
|
-
language
|
|
15280
|
-
});
|
|
15281
|
-
const standardStatements = {};
|
|
15282
|
-
for (const s of selectedStatements) {
|
|
15283
|
-
standardStatements[s.packId + ":" + s.statement.id] = Object.values(s.statement.texts)[0] || "";
|
|
15284
|
-
}
|
|
15285
|
-
if (selectedStatements.length > 0) {
|
|
15286
|
-
console.log(" \u{1F4D0} [Standards] Grounded with " + selectedStatements.length + " verbatim statement(s) from " + new Set(selectedStatements.map((s) => s.packId)).size + " pack(s)");
|
|
15287
|
-
}
|
|
15288
|
-
let lesson = await generateMasterLessonStep({
|
|
15289
|
-
milestone: input.milestone,
|
|
15290
|
-
language,
|
|
15291
|
-
topic: input.topic,
|
|
15292
|
-
targetAudience: input.targetAudience,
|
|
15293
|
-
standardsContext: standardsContext || void 0,
|
|
15294
|
-
modelOptions: input.modelOptions
|
|
15295
|
-
});
|
|
15296
|
-
let auditReport;
|
|
15297
|
-
const lessonGate = gateModeFor(gates, "LESSON");
|
|
15298
|
-
if (lessonGate === "LLM_JUDGE") {
|
|
15299
|
-
auditReport = await judgeMasterLessonStep({
|
|
15300
|
-
lessonId: milestoneId,
|
|
15301
|
-
lesson,
|
|
15302
|
-
language,
|
|
15303
|
-
targetObjectives,
|
|
15304
|
-
standardStatements: Object.keys(standardStatements).length > 0 ? standardStatements : void 0,
|
|
15305
|
-
modelOptions: input.modelOptions
|
|
15306
|
-
});
|
|
15307
|
-
if (auditReport.overallVerdict === "FAIL" || auditReport.overallVerdict === "NEEDS_REVISION") {
|
|
15308
|
-
lesson = await repairMasterLessonStep({
|
|
15309
|
-
milestone: input.milestone,
|
|
15310
|
-
language,
|
|
15311
|
-
topic: input.topic,
|
|
15312
|
-
targetAudience: input.targetAudience,
|
|
15313
|
-
auditReport,
|
|
15314
|
-
standardsContext: standardsContext || void 0,
|
|
15315
|
-
modelOptions: input.modelOptions
|
|
15316
|
-
});
|
|
15317
|
-
}
|
|
15318
|
-
} else if (lessonGate === "HITL") {
|
|
15319
|
-
const hookToken = "gate:lesson:" + milestoneId;
|
|
15320
|
-
console.log(" \u23F8 [Gate] LESSON awaiting HUMAN review (HITL) \u2014 hook " + hookToken);
|
|
15321
|
-
const workflowPkg = await import('workflow');
|
|
15322
|
-
const createHook = workflowPkg.createHook;
|
|
15323
|
-
const hook = createHook({ token: hookToken });
|
|
15324
|
-
const review = await hook;
|
|
15325
|
-
console.log(" \u2705 [Gate] Human verdict: " + (review.approved ? "APPROVED" : "REJECTED") + (review.feedback ? " \u2014 " + review.feedback : ""));
|
|
15326
|
-
if (!review.approved) {
|
|
15327
|
-
const repairReport = {
|
|
15328
|
-
overallVerdict: "NEEDS_REVISION",
|
|
15329
|
-
totalScore: 0,
|
|
15330
|
-
languageAdherencePassed: true,
|
|
15331
|
-
criteria: [],
|
|
15332
|
-
actionableRepairPrompts: review.feedback ? [review.feedback] : ["S\u1EEDa theo ph\u1EA3n h\u1ED3i c\u1EE7a ng\u01B0\u1EDDi duy\u1EC7t"]
|
|
15333
|
-
};
|
|
15334
|
-
lesson = await repairMasterLessonStep({
|
|
15335
|
-
milestone: input.milestone,
|
|
15336
|
-
language,
|
|
15337
|
-
topic: input.topic,
|
|
15338
|
-
targetAudience: input.targetAudience,
|
|
15339
|
-
auditReport: repairReport,
|
|
15340
|
-
standardsContext: standardsContext || void 0,
|
|
15341
|
-
modelOptions: input.modelOptions
|
|
15342
|
-
});
|
|
15343
|
-
const hook2 = createHook({ token: hookToken + ":v2" });
|
|
15344
|
-
const review2 = await hook2;
|
|
15345
|
-
console.log(" \u2705 [Gate] Human verdict (v2): " + (review2.approved ? "APPROVED" : "REJECTED"));
|
|
15346
|
-
if (!review2.approved) {
|
|
15347
|
-
console.log(" \u{1F6D1} [Gate] LESSON rejected twice \u2014 satellites & save BLOCKED");
|
|
15348
|
-
return {
|
|
15349
|
-
milestoneId,
|
|
15350
|
-
milestoneSlug,
|
|
15351
|
-
status: "FAILED",
|
|
15352
|
-
gateBlocked: { artifactType: "LESSON", reason: "HITL_REJECTED_V2", feedback: review2.feedback },
|
|
15353
|
-
artifacts: void 0
|
|
15354
|
-
};
|
|
15355
|
-
}
|
|
15356
|
-
}
|
|
15357
|
-
}
|
|
15358
|
-
const [activity, selfLab, quiz, slides, handout] = await Promise.all([
|
|
15359
|
-
generateActivityStep({ lesson, language, modelOptions: input.modelOptions }),
|
|
15360
|
-
generateSelfLabStep({ milestone: input.milestone, language, targetTechStack: techStack, modelOptions: input.modelOptions }),
|
|
15361
|
-
generateDiagnosticQuizStep({ milestone: input.milestone, language, modelOptions: input.modelOptions }),
|
|
15362
|
-
generateSlidesStep({ lesson, language, modelOptions: input.modelOptions }),
|
|
15363
|
-
generateHandoutStep({ lesson, language, modelOptions: input.modelOptions })
|
|
15364
|
-
]);
|
|
15365
|
-
const codeLab = await generateCodeLabStep({
|
|
15366
|
-
lesson,
|
|
15367
|
-
activity,
|
|
15368
|
-
language,
|
|
15369
|
-
targetTechStack: techStack,
|
|
15370
|
-
modelOptions: input.modelOptions
|
|
15371
|
-
});
|
|
15372
|
-
const satelliteReports = {};
|
|
15373
|
-
const satelliteCandidates = [
|
|
15374
|
-
{ type: "ACT", id: "ACT_" + milestoneId, artifact: activity },
|
|
15375
|
-
{ type: "QUIZ", id: "QUIZ_" + milestoneId, artifact: quiz },
|
|
15376
|
-
{ type: "SLIDE", id: "SLIDE_" + milestoneId, artifact: slides },
|
|
15377
|
-
{ type: "HANDOUT", id: "HANDOUT_" + milestoneId, artifact: handout },
|
|
15378
|
-
{ type: "CODE", id: "CODE_" + milestoneId, artifact: codeLab }
|
|
15379
|
-
];
|
|
15380
|
-
const toJudge = satelliteCandidates.filter((c) => c.artifact && gateModeFor(gates, c.type) === "LLM_JUDGE");
|
|
15381
|
-
if (toJudge.length > 0) {
|
|
15382
|
-
const reports = await Promise.all(
|
|
15383
|
-
toJudge.map(
|
|
15384
|
-
(c) => judgeSatelliteStep({
|
|
15385
|
-
artifactType: c.type,
|
|
15386
|
-
artifactId: c.id,
|
|
15387
|
-
artifact: c.artifact,
|
|
15388
|
-
language,
|
|
15389
|
-
targetObjectives,
|
|
15390
|
-
standardStatements: Object.keys(standardStatements).length > 0 ? standardStatements : void 0,
|
|
15391
|
-
modelOptions: input.modelOptions
|
|
15392
|
-
}).catch((err) => {
|
|
15393
|
-
console.warn(" \u26A0 [Gate] satellite judge failed for " + c.type + ": " + err.message);
|
|
15394
|
-
return void 0;
|
|
15395
|
-
})
|
|
15396
|
-
)
|
|
15397
|
-
);
|
|
15398
|
-
for (let i = 0; i < toJudge.length; i++) {
|
|
15399
|
-
const r = reports[i];
|
|
15400
|
-
if (r) satelliteReports[toJudge[i].type] = r;
|
|
15401
|
-
}
|
|
15402
|
-
}
|
|
15403
|
-
let worksheet;
|
|
15404
|
-
let teacherGuide;
|
|
15405
|
-
let extension;
|
|
15406
|
-
if (bundleTier === "full") {
|
|
15407
|
-
[worksheet, teacherGuide, extension] = await Promise.all([
|
|
15408
|
-
generateWorksheetStep({ lesson, language, modelOptions: input.modelOptions }),
|
|
15409
|
-
generateTeacherGuideStep({ lesson, activity, language, modelOptions: input.modelOptions }),
|
|
15410
|
-
generateExtensionStep({ lesson, activity, language, modelOptions: input.modelOptions })
|
|
15411
|
-
]);
|
|
15412
|
-
}
|
|
15413
|
-
let standardsCoverage;
|
|
15414
|
-
if (packs.length > 0) {
|
|
15415
|
-
standardsCoverage = evaluateStandardsCoverage({
|
|
15416
|
-
packs,
|
|
15417
|
-
objectives: (lesson.learningObjectives || []).map((lo) => ({
|
|
15418
|
-
code: lo.code,
|
|
15419
|
-
standardRefs: lo.standardRefs,
|
|
15420
|
-
conceptRefs: lo.conceptRefs
|
|
15421
|
-
})),
|
|
15422
|
-
// NOTE: ActivityLab has no structured LO linkage yet — activity coverage rows are derived
|
|
15423
|
-
// from LO→quiz paths inside the gate. Wire ACT.loRefs in a future schema revision.
|
|
15424
|
-
activities: [],
|
|
15425
|
-
quizQuestions: (quiz?.questions || []).map((q) => ({ alignedLO: q.alignedLO, alignedAO: q.alignedAO })),
|
|
15426
|
-
assessmentObjectives: quiz?.assessmentObjectives?.map((ao) => ({ aoCode: ao.aoCode, alignedLO: ao.alignedLO }))
|
|
15427
|
-
});
|
|
15428
|
-
console.log(" \u{1F4D0} [Standards Coverage] " + standardsCoverage.summary);
|
|
15429
|
-
const enforce = input.enforceStandardsCoverage ?? true;
|
|
15430
|
-
if (enforce && standardsCoverage.verdict === "FAIL") {
|
|
15431
|
-
console.error(" \u26D4 [Standards Coverage] HARD BLOCK \u2014 " + standardsCoverage.summary);
|
|
15432
|
-
console.error(standardsCoverage.rawMarkdownReport.split("\n").filter((l) => l.startsWith("- [")).slice(0, 10).join("\n"));
|
|
15433
|
-
return {
|
|
15434
|
-
milestoneId,
|
|
15435
|
-
milestoneSlug,
|
|
15436
|
-
status: "FAILED",
|
|
15437
|
-
savedResult: { workspaceDir: "", files: [] },
|
|
15438
|
-
judgeReport: auditReport,
|
|
15439
|
-
standardsCoverage,
|
|
15440
|
-
artifacts: { lesson, activity, codeLab, selfLab, quiz, slides, handout, worksheet, teacherGuide, extension }
|
|
15441
|
-
};
|
|
15442
|
-
}
|
|
15443
|
-
}
|
|
15444
|
-
const savedResult = await saveMilestoneToWorkspaceStep({
|
|
15445
|
-
jobId: input.jobId,
|
|
15446
|
-
milestoneSlug,
|
|
15447
|
-
lesson,
|
|
15448
|
-
activity,
|
|
15449
|
-
codeLab,
|
|
15450
|
-
selfLab,
|
|
15451
|
-
quiz,
|
|
15452
|
-
slides,
|
|
15453
|
-
handout,
|
|
15454
|
-
baseWorkspaceDir: input.baseWorkspaceDir
|
|
15455
|
-
});
|
|
15456
|
-
return {
|
|
15457
|
-
milestoneId,
|
|
15458
|
-
milestoneSlug,
|
|
15459
|
-
status: "SUCCESS",
|
|
15460
|
-
savedResult,
|
|
15461
|
-
judgeReport: auditReport,
|
|
15462
|
-
satelliteJudgeReports: Object.keys(satelliteReports).length > 0 ? satelliteReports : void 0,
|
|
15463
|
-
gatesResolved: gates,
|
|
15464
|
-
standardsCoverage,
|
|
15465
|
-
artifacts: {
|
|
15466
|
-
lesson,
|
|
15467
|
-
activity,
|
|
15468
|
-
codeLab,
|
|
15469
|
-
selfLab,
|
|
15470
|
-
quiz,
|
|
15471
|
-
slides,
|
|
15472
|
-
handout,
|
|
15473
|
-
worksheet,
|
|
15474
|
-
teacherGuide,
|
|
15475
|
-
extension
|
|
15476
|
-
}
|
|
15477
|
-
};
|
|
15478
|
-
}
|
|
15479
|
-
async function generateRoadmapWorkflow(input) {
|
|
15480
|
-
"use workflow";
|
|
15481
|
-
const jobId = input.jobId || `job_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
15482
|
-
const language = input.language || input.roadmap.target_language || "vi";
|
|
15483
|
-
const topic = input.roadmap.topic || input.roadmap.goal || "General Curriculum";
|
|
15484
|
-
const courseTitle = input.roadmap.title || `Curriculum: ${topic}`;
|
|
15485
|
-
const batchSize = input.batchSize || 2;
|
|
15486
|
-
const milestones = input.roadmap.milestones || [];
|
|
15487
|
-
const workspaceManager = new LocalWorkspaceManager(input.baseWorkspaceDir);
|
|
15488
|
-
const workspaceDir = await workspaceManager.initJobWorkspace(jobId, {
|
|
15489
|
-
courseTitle,
|
|
15490
|
-
topic,
|
|
15491
|
-
language,
|
|
15492
|
-
totalMilestones: milestones.length
|
|
15493
|
-
});
|
|
15494
|
-
const milestoneOutcomes = [];
|
|
15495
|
-
for (let i = 0; i < milestones.length; i += batchSize) {
|
|
15496
|
-
const batch = milestones.slice(i, i + batchSize);
|
|
15497
|
-
const batchSettled = await Promise.allSettled(
|
|
15498
|
-
batch.map(
|
|
15499
|
-
(milestone) => generateMilestoneWorkflow({
|
|
15500
|
-
jobId,
|
|
15501
|
-
milestone,
|
|
15502
|
-
language,
|
|
15503
|
-
topic,
|
|
15504
|
-
targetAudience: input.roadmap.target_audience,
|
|
15505
|
-
techStack: input.roadmap.tech_stack || milestone.tech_keywords,
|
|
15506
|
-
bundleTier: input.bundleTier,
|
|
15507
|
-
gateSettings: input.gateSettings,
|
|
15508
|
-
baseWorkspaceDir: input.baseWorkspaceDir,
|
|
15509
|
-
modelOptions: input.modelOptions
|
|
15510
|
-
})
|
|
15511
|
-
)
|
|
15512
|
-
);
|
|
15513
|
-
for (const [idx, outcome] of batchSettled.entries()) {
|
|
15514
|
-
const targetMilestone = batch[idx];
|
|
15515
|
-
const mId = targetMilestone.id || targetMilestone.concept_code || `M${i + idx + 1}`;
|
|
15516
|
-
if (outcome.status === "fulfilled") {
|
|
15517
|
-
milestoneOutcomes.push({
|
|
15518
|
-
milestoneId: mId,
|
|
15519
|
-
status: "FULFILLED",
|
|
15520
|
-
result: outcome.value
|
|
15521
|
-
});
|
|
15522
|
-
} else {
|
|
15523
|
-
milestoneOutcomes.push({
|
|
15524
|
-
milestoneId: mId,
|
|
15525
|
-
status: "REJECTED",
|
|
15526
|
-
error: outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason)
|
|
15527
|
-
});
|
|
15528
|
-
}
|
|
15529
|
-
}
|
|
15530
|
-
if (i + batchSize < milestones.length) {
|
|
15531
|
-
await sleep("2s");
|
|
15532
|
-
}
|
|
15533
|
-
}
|
|
15534
|
-
const successfulMilestones = milestoneOutcomes.filter((m) => m.status === "FULFILLED").length;
|
|
15535
|
-
const failedMilestones = milestoneOutcomes.filter((m) => m.status === "REJECTED").length;
|
|
15536
|
-
let gitPublishResult = void 0;
|
|
15537
|
-
let supabasePublishResult = void 0;
|
|
15538
|
-
if (input.gitPublishOptions) {
|
|
15539
|
-
gitPublishResult = await publishToGitStep({
|
|
15540
|
-
jobId,
|
|
15541
|
-
localJobDir: workspaceDir,
|
|
15542
|
-
...input.gitPublishOptions
|
|
15543
|
-
});
|
|
15544
|
-
}
|
|
15545
|
-
if (input.supabasePublishOptions) {
|
|
15546
|
-
supabasePublishResult = await publishToSupabaseStep({
|
|
15547
|
-
jobId,
|
|
15548
|
-
courseTitle,
|
|
15549
|
-
topic,
|
|
15550
|
-
language,
|
|
15551
|
-
milestones: milestoneOutcomes.filter((m) => m.status === "FULFILLED" && m.result).map((m) => ({
|
|
15552
|
-
milestoneId: m.milestoneId,
|
|
15553
|
-
milestoneName: m.result.savedResult.milestoneSlug,
|
|
15554
|
-
lessonSlug: m.result.savedResult.milestoneSlug
|
|
15555
|
-
})),
|
|
15556
|
-
...input.supabasePublishOptions
|
|
15557
|
-
});
|
|
15558
|
-
}
|
|
15559
|
-
return {
|
|
15560
|
-
jobId,
|
|
15561
|
-
courseTitle,
|
|
15562
|
-
topic,
|
|
15563
|
-
language,
|
|
15564
|
-
totalMilestones: milestones.length,
|
|
15565
|
-
successfulMilestones,
|
|
15566
|
-
failedMilestones,
|
|
15567
|
-
results: milestoneOutcomes,
|
|
15568
|
-
gitPublishResult,
|
|
15569
|
-
supabasePublishResult,
|
|
15570
|
-
workspaceDir
|
|
15571
|
-
};
|
|
15572
|
-
}
|
|
15573
|
-
|
|
15574
|
-
// src/workflow/workflows/singleArtifactWorkflow.ts
|
|
15575
|
-
async function executeSingleArtifactStep(request) {
|
|
15576
|
-
"use step";
|
|
15577
|
-
const t0 = Date.now();
|
|
15578
|
-
console.log(` \u23F3 [Step: Single Artifact] Generating ${request.artifactType.toUpperCase()} for "${request.topic.slice(0, 35)}"...`);
|
|
15579
|
-
const res = await withRateLimitBackoff({
|
|
15580
|
-
stepName: `generate-single-artifact-${request.artifactType}-${(request.topic || "topic").slice(0, 20)}`,
|
|
15581
|
-
fn: async () => generateSingleArtifact(request)
|
|
15582
|
-
});
|
|
15583
|
-
console.log(` \u2705 [Step: Single Artifact] Done in ${((Date.now() - t0) / 1e3).toFixed(1)}s (File: "${res.filename}")`);
|
|
15584
|
-
return res;
|
|
15585
|
-
}
|
|
15586
|
-
async function generateSingleArtifactWorkflow(request) {
|
|
15587
|
-
"use workflow";
|
|
15588
|
-
return executeSingleArtifactStep(request);
|
|
15589
|
-
}
|
|
15590
|
-
|
|
15591
|
-
// src/index.ts
|
|
15592
|
-
init_errors();
|
|
15593
|
-
|
|
15594
|
-
// src/evaluators/deterministicStructuralLinter.ts
|
|
15595
|
-
var DeterministicStructuralLinter = class {
|
|
15596
|
-
/**
|
|
15597
|
-
* Validates structural invariants across a complete lesson bundle.
|
|
15598
|
-
*/
|
|
15599
|
-
static lintBundle(input) {
|
|
15600
|
-
const { lesson, quiz, activity, slides, codeLab } = input;
|
|
15601
|
-
const findings = [];
|
|
15602
|
-
const strengths = [];
|
|
15603
|
-
let score = 100;
|
|
15604
|
-
const baseLessonId = lesson.lessonId;
|
|
15605
|
-
const baseLanguage = lesson.language;
|
|
15606
|
-
if (!lesson.title || lesson.title.trim().length === 0) {
|
|
15607
|
-
score -= 20;
|
|
15608
|
-
findings.push({
|
|
15609
|
-
id: "struct_missing_lesson_title",
|
|
15610
|
-
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
15611
|
-
severity: "CRITICAL",
|
|
15612
|
-
title: "Missing Lesson Title",
|
|
15613
|
-
description: "Lesson plan has an empty or whitespace title.",
|
|
15614
|
-
remediationAdvice: "Provide a non-empty lesson title."
|
|
15615
|
-
});
|
|
15616
|
-
}
|
|
15617
|
-
if (!lesson.learningObjectives || lesson.learningObjectives.length === 0) {
|
|
15618
|
-
score -= 25;
|
|
15619
|
-
findings.push({
|
|
15620
|
-
id: "struct_empty_learning_objectives",
|
|
15621
|
-
dimension: "CONSTRUCTIVE_ALIGNMENT",
|
|
15622
|
-
severity: "CRITICAL",
|
|
15623
|
-
title: "Empty Learning Objectives Array",
|
|
15624
|
-
description: "Lesson plan contains 0 learning objectives.",
|
|
15625
|
-
remediationAdvice: "Declare at least 2 structured Learning Objectives in the schema."
|
|
15626
|
-
});
|
|
15627
|
-
}
|
|
15628
|
-
if (!lesson.sections || lesson.sections.length === 0) {
|
|
15629
|
-
score -= 25;
|
|
15630
|
-
findings.push({
|
|
15631
|
-
id: "struct_empty_lesson_sections",
|
|
15632
|
-
dimension: "5E_INSTRUCTIONAL_FIDELITY",
|
|
15633
|
-
severity: "CRITICAL",
|
|
15634
|
-
title: "Empty Lesson Sections Array",
|
|
15635
|
-
description: "Lesson plan contains no instructional sections.",
|
|
15636
|
-
remediationAdvice: "Provide structured lesson flow sections."
|
|
15637
|
-
});
|
|
15638
|
-
}
|
|
15639
|
-
if (quiz && quiz.quizId !== baseLessonId && !quiz.quizId.includes(baseLessonId)) {
|
|
15640
|
-
score -= 15;
|
|
15641
|
-
findings.push({
|
|
15642
|
-
id: "struct_quiz_id_mismatch",
|
|
15643
|
-
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
15644
|
-
severity: "MAJOR",
|
|
15645
|
-
title: "Quiz ID Contract Mismatch",
|
|
15646
|
-
description: `Quiz ID "${quiz.quizId}" does not match Lesson ID "${baseLessonId}".`,
|
|
15647
|
-
remediationAdvice: `Sync Quiz quizId to "${baseLessonId}".`,
|
|
15648
|
-
affectedElement: quiz.quizId
|
|
15649
|
-
});
|
|
15650
|
-
}
|
|
15651
|
-
if (activity && activity.lessonId !== baseLessonId) {
|
|
15652
|
-
score -= 15;
|
|
15653
|
-
findings.push({
|
|
15654
|
-
id: "struct_act_id_mismatch",
|
|
15655
|
-
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
15656
|
-
severity: "MAJOR",
|
|
15657
|
-
title: "Activity Lesson ID Contract Mismatch",
|
|
15658
|
-
description: `Activity lessonId "${activity.lessonId}" does not match Lesson ID "${baseLessonId}".`,
|
|
15659
|
-
remediationAdvice: `Sync Activity lessonId to "${baseLessonId}".`,
|
|
15660
|
-
affectedElement: activity.lessonId
|
|
15661
|
-
});
|
|
15662
|
-
}
|
|
15663
|
-
if (slides && slides.lessonId !== baseLessonId) {
|
|
15664
|
-
score -= 15;
|
|
15665
|
-
findings.push({
|
|
15666
|
-
id: "struct_slides_id_mismatch",
|
|
15667
|
-
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
15668
|
-
severity: "MAJOR",
|
|
15669
|
-
title: "Slide Deck Lesson ID Contract Mismatch",
|
|
15670
|
-
description: `Slide deck lessonId "${slides.lessonId}" does not match Lesson ID "${baseLessonId}".`,
|
|
15671
|
-
remediationAdvice: `Sync Slide deck lessonId to "${baseLessonId}".`,
|
|
15672
|
-
affectedElement: slides.lessonId
|
|
15673
|
-
});
|
|
15674
|
-
}
|
|
15675
|
-
const satellites = [
|
|
15676
|
-
{ type: "QUIZ", lang: quiz?.language },
|
|
15677
|
-
{ type: "ACT", lang: activity?.language },
|
|
15678
|
-
{ type: "SLIDE", lang: slides?.language }
|
|
15679
|
-
];
|
|
15680
|
-
for (const sat of satellites) {
|
|
15681
|
-
if (sat.lang && sat.lang.toLowerCase() !== baseLanguage.toLowerCase()) {
|
|
15682
|
-
score -= 25;
|
|
15683
|
-
findings.push({
|
|
15684
|
-
id: `struct_language_mismatch_${sat.type}`,
|
|
15685
|
-
dimension: "CROSS_ARTIFACT_ZERO_DRIFT",
|
|
15686
|
-
severity: "CRITICAL",
|
|
15687
|
-
title: `Language Policy Inconsistency in ${sat.type}`,
|
|
15688
|
-
description: `Master Lesson is in "${baseLanguage}" but ${sat.type} is declared in "${sat.lang}".`,
|
|
15689
|
-
remediationAdvice: `Set ${sat.type} language to "${baseLanguage}".`
|
|
15690
|
-
});
|
|
15691
|
-
}
|
|
15692
|
-
}
|
|
15693
|
-
if (quiz && quiz.questions) {
|
|
15694
|
-
for (let i = 0; i < quiz.questions.length; i++) {
|
|
15695
|
-
const q = quiz.questions[i];
|
|
15696
|
-
const qId = q.id || `Q${i + 1}`;
|
|
15697
|
-
const options = q.options || [];
|
|
15698
|
-
if (options.length < 4) {
|
|
15699
|
-
score -= 10;
|
|
15700
|
-
findings.push({
|
|
15701
|
-
id: `struct_quiz_option_count_${qId}`,
|
|
15702
|
-
dimension: "MISCONCEPTION_RIGOR",
|
|
15703
|
-
severity: "MAJOR",
|
|
15704
|
-
title: `Structural Option Count Error in ${qId}`,
|
|
15705
|
-
description: `Question ${qId} has ${options.length} options (standard schema requires 4).`,
|
|
15706
|
-
remediationAdvice: "Ensure each question has 4 options (A, B, C, D).",
|
|
15707
|
-
affectedElement: qId
|
|
15708
|
-
});
|
|
15709
|
-
}
|
|
15710
|
-
const correctCount = options.filter((o) => o.isCorrect).length;
|
|
15711
|
-
if (correctCount !== 1) {
|
|
15712
|
-
score -= 20;
|
|
15713
|
-
findings.push({
|
|
15714
|
-
id: `struct_quiz_key_count_${qId}`,
|
|
15715
|
-
dimension: "MISCONCEPTION_RIGOR",
|
|
15716
|
-
severity: "CRITICAL",
|
|
15717
|
-
title: `Key Assignment Error in ${qId}`,
|
|
15718
|
-
description: `Question ${qId} has ${correctCount} correct options (must be exactly 1).`,
|
|
15719
|
-
remediationAdvice: "Set `isCorrect: true` on exactly 1 option.",
|
|
15720
|
-
affectedElement: qId
|
|
15721
|
-
});
|
|
15722
|
-
}
|
|
15723
|
-
}
|
|
15724
|
-
}
|
|
15725
|
-
if (activity?.materialsBOM?.hardware && activity.materialsBOM.hardware.length > 0) {
|
|
15726
|
-
const hwText = activity.materialsBOM.hardware.join(" ").toLowerCase();
|
|
15727
|
-
const hasLED = hwText.includes("led");
|
|
15728
|
-
const hasResistor = hwText.includes("\u0111i\u1EC7n tr\u1EDF") || hwText.includes("resistor") || hwText.includes("220") || hwText.includes("330") || hwText.includes("1k");
|
|
15729
|
-
if (hasLED && !hasResistor) {
|
|
15730
|
-
score -= 20;
|
|
15731
|
-
findings.push({
|
|
15732
|
-
id: "struct_hardware_unsafe_led_no_resistor",
|
|
15733
|
-
dimension: "TECHNICAL_AUTHENTICITY",
|
|
15734
|
-
severity: "CRITICAL",
|
|
15735
|
-
title: "Unsafe Circuit BOM: LED without Current-Limiting Resistor",
|
|
15736
|
-
description: "Hardware BOM includes LED without a 220\u03A9-1k\u03A9 resistor, causing circuit overload.",
|
|
15737
|
-
remediationAdvice: "Add a 220\u03A9 current-limiting resistor to the hardware materials list."
|
|
15738
|
-
});
|
|
15739
|
-
}
|
|
15740
|
-
}
|
|
15741
|
-
score = Math.max(0, Math.min(100, score));
|
|
15742
|
-
const passed = score >= 80 && !findings.some((f) => f.severity === "CRITICAL");
|
|
15743
|
-
if (passed) {
|
|
15744
|
-
strengths.push("Deterministic structure, ID contracts, and schema invariants strictly verified.");
|
|
15745
|
-
}
|
|
15746
|
-
return {
|
|
15747
|
-
passed,
|
|
15748
|
-
structuralScore: score,
|
|
15749
|
-
findings,
|
|
15750
|
-
strengths
|
|
15751
|
-
};
|
|
15752
|
-
}
|
|
15753
|
-
};
|
|
15754
|
-
|
|
15755
|
-
// src/evaluators/academicAuditor.ts
|
|
15756
|
-
var AcademicAuditor = class {
|
|
15757
|
-
/**
|
|
15758
|
-
* Evaluates a complete lesson bundle.
|
|
15759
|
-
* Step 1 (Deterministic): Fast structural, contract, schema, and safety linting.
|
|
15760
|
-
* Step 2 (Semantic LLM-as-a-Judge): Deep pedagogical, cognitive (Bloom), and misconception analysis with live frontier LLM.
|
|
15761
|
-
*/
|
|
15762
|
-
static async auditLessonBundle(input) {
|
|
15763
|
-
const { lesson, quiz, activity, slides, codeLab, modelOptions, executeLLMJudge = true } = input;
|
|
15764
|
-
const structuralResult = DeterministicStructuralLinter.lintBundle({
|
|
15765
|
-
lesson,
|
|
15766
|
-
quiz,
|
|
15767
|
-
activity,
|
|
15768
|
-
slides,
|
|
15769
|
-
codeLab
|
|
15770
|
-
});
|
|
15771
|
-
const allFindings = [...structuralResult.findings];
|
|
15772
|
-
const strengths = [...structuralResult.strengths];
|
|
15773
|
-
let semanticScore = null;
|
|
15774
|
-
let semanticVerdict = "PASS";
|
|
15775
|
-
if (executeLLMJudge) {
|
|
15776
|
-
try {
|
|
15777
|
-
const judgeReport = await auditCurriculumQualityFlow({
|
|
15778
|
-
targetArtifactType: "LESSON_BUNDLE",
|
|
15779
|
-
lessonId: lesson.lessonId,
|
|
15780
|
-
expectedLanguage: lesson.language,
|
|
15781
|
-
targetObjectives: (lesson.learningObjectives || []).map((lo) => ({
|
|
15782
|
-
code: lo.code,
|
|
15783
|
-
description: lo.description,
|
|
15784
|
-
bloomLevel: lo.bloomLevel
|
|
15785
|
-
})),
|
|
15786
|
-
generatedContentJson: JSON.stringify({ lesson, quiz, activity, slides, codeLab }),
|
|
15787
|
-
modelOptions
|
|
15788
|
-
});
|
|
15789
|
-
semanticScore = judgeReport.totalScore;
|
|
15790
|
-
semanticVerdict = judgeReport.overallVerdict;
|
|
15791
|
-
for (const criterion of judgeReport.criteria) {
|
|
15792
|
-
if (!criterion.passed) {
|
|
15793
|
-
allFindings.push({
|
|
15794
|
-
id: `llm_judge_${criterion.name.toLowerCase().replace(/\s+/g, "_")}`,
|
|
15795
|
-
dimension: "CONSTRUCTIVE_ALIGNMENT",
|
|
15796
|
-
severity: criterion.score < 50 ? "CRITICAL" : "MAJOR",
|
|
15797
|
-
title: `LLM-as-Judge Finding: ${criterion.name}`,
|
|
15798
|
-
description: criterion.feedback,
|
|
15799
|
-
remediationAdvice: judgeReport.actionableRepairPrompts.join("; ") || "Refine prompt context."
|
|
15800
|
-
});
|
|
15801
|
-
} else {
|
|
15802
|
-
strengths.push(`[LLM-Judge] ${criterion.name}: ${criterion.feedback}`);
|
|
15803
|
-
}
|
|
15804
|
-
}
|
|
15805
|
-
} catch (err) {
|
|
15806
|
-
semanticScore = null;
|
|
15807
|
-
semanticVerdict = "FAIL";
|
|
15808
|
-
allFindings.push({
|
|
15809
|
-
id: "llm_judge_connection_error",
|
|
15810
|
-
dimension: "CONSTRUCTIVE_ALIGNMENT",
|
|
15811
|
-
severity: "MINOR",
|
|
15812
|
-
title: "LLM-as-Judge Skipped / Fallback",
|
|
15813
|
-
description: `Semantic inference error: ${err.message || String(err)}`,
|
|
15814
|
-
remediationAdvice: "Check API credentials for LLM-as-Judge."
|
|
15815
|
-
});
|
|
15816
|
-
}
|
|
14844
|
+
const allFindings = [...structuralResult.findings];
|
|
14845
|
+
const strengths = [...structuralResult.strengths];
|
|
14846
|
+
let semanticScore = null;
|
|
14847
|
+
let semanticVerdict = "PASS";
|
|
14848
|
+
if (executeLLMJudge) {
|
|
14849
|
+
try {
|
|
14850
|
+
const judgeReport = await auditCurriculumQualityFlow({
|
|
14851
|
+
targetArtifactType: "LESSON_BUNDLE",
|
|
14852
|
+
lessonId: lesson.lessonId,
|
|
14853
|
+
expectedLanguage: lesson.language,
|
|
14854
|
+
targetObjectives: (lesson.learningObjectives || []).map((lo) => ({
|
|
14855
|
+
code: lo.code,
|
|
14856
|
+
description: lo.description,
|
|
14857
|
+
bloomLevel: lo.bloomLevel
|
|
14858
|
+
})),
|
|
14859
|
+
generatedContentJson: JSON.stringify({ lesson, quiz, activity, slides, codeLab }),
|
|
14860
|
+
modelOptions
|
|
14861
|
+
});
|
|
14862
|
+
semanticScore = judgeReport.totalScore;
|
|
14863
|
+
semanticVerdict = judgeReport.overallVerdict;
|
|
14864
|
+
for (const criterion of judgeReport.criteria) {
|
|
14865
|
+
if (!criterion.passed) {
|
|
14866
|
+
allFindings.push({
|
|
14867
|
+
id: `llm_judge_${criterion.name.toLowerCase().replace(/\s+/g, "_")}`,
|
|
14868
|
+
dimension: "CONSTRUCTIVE_ALIGNMENT",
|
|
14869
|
+
severity: criterion.score < 50 ? "CRITICAL" : "MAJOR",
|
|
14870
|
+
title: `LLM-as-Judge Finding: ${criterion.name}`,
|
|
14871
|
+
description: criterion.feedback,
|
|
14872
|
+
remediationAdvice: judgeReport.actionableRepairPrompts.join("; ") || "Refine prompt context."
|
|
14873
|
+
});
|
|
14874
|
+
} else {
|
|
14875
|
+
strengths.push(`[LLM-Judge] ${criterion.name}: ${criterion.feedback}`);
|
|
14876
|
+
}
|
|
14877
|
+
}
|
|
14878
|
+
} catch (err) {
|
|
14879
|
+
semanticScore = null;
|
|
14880
|
+
semanticVerdict = "FAIL";
|
|
14881
|
+
allFindings.push({
|
|
14882
|
+
id: "llm_judge_connection_error",
|
|
14883
|
+
dimension: "CONSTRUCTIVE_ALIGNMENT",
|
|
14884
|
+
severity: "MINOR",
|
|
14885
|
+
title: "LLM-as-Judge Skipped / Fallback",
|
|
14886
|
+
description: `Semantic inference error: ${err.message || String(err)}`,
|
|
14887
|
+
remediationAdvice: "Check API credentials for LLM-as-Judge."
|
|
14888
|
+
});
|
|
14889
|
+
}
|
|
15817
14890
|
}
|
|
15818
14891
|
const criticalCount = allFindings.filter((f) => f.severity === "CRITICAL").length;
|
|
15819
14892
|
const overallScore = executeLLMJudge && semanticScore !== null ? Math.round(structuralResult.structuralScore * 0.4 + semanticScore * 0.6) : structuralResult.structuralScore;
|
|
@@ -16694,32 +15767,316 @@ var MisconceptionEvaluator = class {
|
|
|
16694
15767
|
missingExplanation = true;
|
|
16695
15768
|
}
|
|
16696
15769
|
}
|
|
16697
|
-
if (missingExplanation) {
|
|
16698
|
-
score -= 10;
|
|
16699
|
-
findings.push({
|
|
16700
|
-
id: `misconception_shallow_explanation_${qId}`,
|
|
16701
|
-
dimension: "MISCONCEPTION_RIGOR",
|
|
16702
|
-
severity: "MAJOR",
|
|
16703
|
-
title: `Shallow Distractor Explanations in ${qId}`,
|
|
16704
|
-
description: `Question ${qId} lacks detailed pedagogical explanations for all options. Students and teachers cannot diagnose root causes without option-level rationale.`,
|
|
16705
|
-
remediationAdvice: "For EVERY option (A, B, C, D), explicitly write why the choice is correct or what mental misconception it represents.",
|
|
16706
|
-
affectedElement: qId
|
|
15770
|
+
if (missingExplanation) {
|
|
15771
|
+
score -= 10;
|
|
15772
|
+
findings.push({
|
|
15773
|
+
id: `misconception_shallow_explanation_${qId}`,
|
|
15774
|
+
dimension: "MISCONCEPTION_RIGOR",
|
|
15775
|
+
severity: "MAJOR",
|
|
15776
|
+
title: `Shallow Distractor Explanations in ${qId}`,
|
|
15777
|
+
description: `Question ${qId} lacks detailed pedagogical explanations for all options. Students and teachers cannot diagnose root causes without option-level rationale.`,
|
|
15778
|
+
remediationAdvice: "For EVERY option (A, B, C, D), explicitly write why the choice is correct or what mental misconception it represents.",
|
|
15779
|
+
affectedElement: qId
|
|
15780
|
+
});
|
|
15781
|
+
} else {
|
|
15782
|
+
questionsWithFullExplanations++;
|
|
15783
|
+
}
|
|
15784
|
+
}
|
|
15785
|
+
if (questionsWithFullExplanations === questions.length && questions.length >= 3) {
|
|
15786
|
+
strengths.push("All quiz questions feature rigorous 4-option breakdown with comprehensive misconception analysis.");
|
|
15787
|
+
}
|
|
15788
|
+
score = Math.max(0, Math.min(100, score));
|
|
15789
|
+
return {
|
|
15790
|
+
score,
|
|
15791
|
+
weight: 0.2,
|
|
15792
|
+
passed: score >= 75 && !findings.some((f) => f.severity === "CRITICAL"),
|
|
15793
|
+
strengths,
|
|
15794
|
+
findings
|
|
15795
|
+
};
|
|
15796
|
+
}
|
|
15797
|
+
};
|
|
15798
|
+
|
|
15799
|
+
// src/standards/standardsCoverageGate.ts
|
|
15800
|
+
function resolveStatementRef(ref, packs) {
|
|
15801
|
+
const [head, ...rest] = ref.split(":");
|
|
15802
|
+
const candidatePacks = rest.length > 0 ? packs.filter((p) => p.manifest.id === head) : packs;
|
|
15803
|
+
const statementId = rest.length > 0 ? rest.join(":") : ref;
|
|
15804
|
+
for (const p of candidatePacks) {
|
|
15805
|
+
if (p.statements.some((s) => s.id === statementId)) return { pack: p, statementId };
|
|
15806
|
+
}
|
|
15807
|
+
return null;
|
|
15808
|
+
}
|
|
15809
|
+
function evaluateStandardsCoverage(input) {
|
|
15810
|
+
const rows = [];
|
|
15811
|
+
const aoToLo = /* @__PURE__ */ new Map();
|
|
15812
|
+
for (const ao of input.assessmentObjectives ?? []) aoToLo.set(ao.aoCode, ao.alignedLO);
|
|
15813
|
+
const loToRefs = /* @__PURE__ */ new Map();
|
|
15814
|
+
for (const lo of input.objectives) {
|
|
15815
|
+
loToRefs.set(lo.code, new Set(lo.standardRefs ?? []));
|
|
15816
|
+
}
|
|
15817
|
+
const taughtLOs = /* @__PURE__ */ new Set();
|
|
15818
|
+
for (const act of input.activities ?? []) for (const lo of act.lo) taughtLOs.add(lo);
|
|
15819
|
+
const assessedLOs = /* @__PURE__ */ new Set();
|
|
15820
|
+
for (const q of input.quizQuestions) {
|
|
15821
|
+
if (q.alignedLO) assessedLOs.add(q.alignedLO);
|
|
15822
|
+
if (q.alignedAO) {
|
|
15823
|
+
const lo = aoToLo.get(q.alignedAO);
|
|
15824
|
+
if (lo) assessedLOs.add(lo);
|
|
15825
|
+
}
|
|
15826
|
+
}
|
|
15827
|
+
for (const pack of input.packs) {
|
|
15828
|
+
const mappingByStatement = /* @__PURE__ */ new Map();
|
|
15829
|
+
for (const m of pack.mappings ?? []) {
|
|
15830
|
+
const prev = mappingByStatement.get(m.statementId);
|
|
15831
|
+
if (!prev || prev !== "covers" && m.kind === "covers" || prev === "extends" && m.kind !== "extends") {
|
|
15832
|
+
mappingByStatement.set(m.statementId, m.kind);
|
|
15833
|
+
}
|
|
15834
|
+
}
|
|
15835
|
+
for (const statement of pack.statements) {
|
|
15836
|
+
const refFull = `${pack.manifest.id}:${statement.id}`;
|
|
15837
|
+
const issues = [];
|
|
15838
|
+
const los = input.objectives.filter((lo) => (lo.standardRefs ?? []).some((r) => r === statement.id || r === refFull)).map((lo) => lo.code);
|
|
15839
|
+
const kind = mappingByStatement.get(statement.id);
|
|
15840
|
+
const hasMapping = kind !== void 0;
|
|
15841
|
+
const isComplianceRelevant = kind === "covers";
|
|
15842
|
+
const hasActivity = los.some((lo) => taughtLOs.has(lo));
|
|
15843
|
+
const hasAssessment = los.some((lo) => assessedLOs.has(lo));
|
|
15844
|
+
let status;
|
|
15845
|
+
if (!hasMapping) status = "UNMAPPED";
|
|
15846
|
+
else if (!isComplianceRelevant) status = "PARTIAL";
|
|
15847
|
+
else if (los.length > 0 && hasActivity && hasAssessment) status = "COVERED";
|
|
15848
|
+
else status = "UNCOVERED";
|
|
15849
|
+
if (status === "UNCOVERED") {
|
|
15850
|
+
if (los.length === 0) issues.push("No learning objective anchors this statement (missing standardRefs).");
|
|
15851
|
+
else {
|
|
15852
|
+
if (!hasActivity) issues.push(`Anchored LO(s) ${los.join(", ")} have no activity in lesson flow.`);
|
|
15853
|
+
if (!hasAssessment) issues.push(`Anchored LO(s) ${los.join(", ")} are not measured by any quiz question.`);
|
|
15854
|
+
}
|
|
15855
|
+
}
|
|
15856
|
+
rows.push({
|
|
15857
|
+
packId: pack.manifest.id,
|
|
15858
|
+
statementId: statement.id,
|
|
15859
|
+
statementText: Object.values(statement.texts)[0] ?? "",
|
|
15860
|
+
status,
|
|
15861
|
+
objectives: los,
|
|
15862
|
+
hasActivity,
|
|
15863
|
+
hasAssessment,
|
|
15864
|
+
issues
|
|
15865
|
+
});
|
|
15866
|
+
}
|
|
15867
|
+
}
|
|
15868
|
+
for (const lo of input.objectives) {
|
|
15869
|
+
for (const r of lo.standardRefs ?? []) {
|
|
15870
|
+
if (!resolveStatementRef(r, input.packs)) {
|
|
15871
|
+
rows.push({
|
|
15872
|
+
packId: "(unresolved)",
|
|
15873
|
+
statementId: r,
|
|
15874
|
+
statementText: "",
|
|
15875
|
+
status: "UNCOVERED",
|
|
15876
|
+
objectives: [lo.code],
|
|
15877
|
+
hasActivity: false,
|
|
15878
|
+
hasAssessment: false,
|
|
15879
|
+
issues: [`standardRef "${r}" does not exist in any adopted pack \u2014 likely a hallucinated or stale ID`]
|
|
16707
15880
|
});
|
|
16708
|
-
} else {
|
|
16709
|
-
questionsWithFullExplanations++;
|
|
16710
15881
|
}
|
|
16711
15882
|
}
|
|
16712
|
-
|
|
16713
|
-
|
|
15883
|
+
}
|
|
15884
|
+
const complianceRows = rows.filter((r) => r.status !== "UNMAPPED" && r.status !== "PARTIAL");
|
|
15885
|
+
const covered = complianceRows.filter((r) => r.status === "COVERED").length;
|
|
15886
|
+
const coveragePct = complianceRows.length === 0 ? 100 : Math.round(covered / complianceRows.length * 100);
|
|
15887
|
+
const unresolvedCount = rows.filter((r) => r.packId === "(unresolved)").length;
|
|
15888
|
+
const verdict = unresolvedCount > 0 || coveragePct < 60 ? "FAIL" : coveragePct < 100 ? "WARN" : "PASS";
|
|
15889
|
+
const lines = [
|
|
15890
|
+
"# Standards Coverage Report",
|
|
15891
|
+
"",
|
|
15892
|
+
`- Verdict: **${verdict}**`,
|
|
15893
|
+
`- Compliance coverage: **${coveragePct}%** (${covered}/${complianceRows.length} "covers" statements fully taught + assessed)`,
|
|
15894
|
+
`- Unresolved standardRefs: ${unresolvedCount}`,
|
|
15895
|
+
"",
|
|
15896
|
+
"| Pack | Statement | Status | LOs | Activity | Assessment |",
|
|
15897
|
+
"|---|---|---|---|---|---|",
|
|
15898
|
+
...rows.map(
|
|
15899
|
+
(r) => `|${r.packId}|${r.statementId}|${r.status}|${r.objectives.join(", ") || "\u2014"}|${r.hasActivity ? "\u2713" : "\u2717"}|${r.hasAssessment ? "\u2713" : "\u2717"}|`
|
|
15900
|
+
)
|
|
15901
|
+
];
|
|
15902
|
+
const issueLines = rows.filter((r) => r.issues.length > 0).flatMap((r) => r.issues.map((i) => `- [${r.packId}:${r.statementId}] ${i}`));
|
|
15903
|
+
if (issueLines.length > 0) lines.push("", "## Issues", ...issueLines);
|
|
15904
|
+
return {
|
|
15905
|
+
verdict,
|
|
15906
|
+
coveragePct,
|
|
15907
|
+
rows,
|
|
15908
|
+
summary: `Standards coverage ${coveragePct}% \u2014 verdict ${verdict}`,
|
|
15909
|
+
rawMarkdownReport: lines.join("\n")
|
|
15910
|
+
};
|
|
15911
|
+
}
|
|
15912
|
+
var StandardsRegistryAdapter = class {
|
|
15913
|
+
client;
|
|
15914
|
+
constructor(config = {}) {
|
|
15915
|
+
if (config.client) {
|
|
15916
|
+
this.client = config.client;
|
|
15917
|
+
return;
|
|
16714
15918
|
}
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16721
|
-
|
|
16722
|
-
|
|
15919
|
+
const url = config.supabaseUrl || process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.SUPABASE_URL || "";
|
|
15920
|
+
const key = config.supabaseServiceRoleKey || process.env.SUPABASE_SERVICE_ROLE_KEY || config.supabaseAnonKey || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "";
|
|
15921
|
+
if (!url || !key) {
|
|
15922
|
+
throw new Error("StandardsRegistryAdapter: Supabase URL/key missing (pass client or env).");
|
|
15923
|
+
}
|
|
15924
|
+
this.client = createClient(url, key);
|
|
15925
|
+
}
|
|
15926
|
+
// ─── Intake (write path — service role) ───────────────────────────────────
|
|
15927
|
+
/** Persist a schema-validated pack as a new framework (status=draft). */
|
|
15928
|
+
async importPack(pack, opts) {
|
|
15929
|
+
const parsed = FrameworkPackSchema.safeParse(pack);
|
|
15930
|
+
if (!parsed.success) {
|
|
15931
|
+
throw new Error("importPack: pack failed schema validation: " + parsed.error.issues.map((i) => i.path.join(".") + ": " + i.message).join("; "));
|
|
15932
|
+
}
|
|
15933
|
+
const p = parsed.data;
|
|
15934
|
+
const { data: fw, error: fwErr } = await this.client.from("standards_frameworks").insert({
|
|
15935
|
+
pack_id: p.manifest.id,
|
|
15936
|
+
content_version: p.manifest.contentVersion,
|
|
15937
|
+
name: p.manifest.name,
|
|
15938
|
+
spec_version: p.manifest.specVersion,
|
|
15939
|
+
subject: p.manifest.subject,
|
|
15940
|
+
languages: p.manifest.languages,
|
|
15941
|
+
grade_model: p.manifest.gradeModel,
|
|
15942
|
+
provenance: p.manifest.provenance,
|
|
15943
|
+
trust: p.manifest.trust,
|
|
15944
|
+
status: "draft",
|
|
15945
|
+
organization_code: opts?.organizationCode ?? (p.manifest.trust === "verified" ? null : p.manifest.provenance.importedBy?.replace(/^org:/, "") || null),
|
|
15946
|
+
original_file_path: opts?.originalFilePath ?? null,
|
|
15947
|
+
created_by: opts?.createdBy ?? null
|
|
15948
|
+
}).select("id").single();
|
|
15949
|
+
if (fwErr) throw new Error("importPack: framework insert failed: " + fwErr.message);
|
|
15950
|
+
const frameworkId = fw.id;
|
|
15951
|
+
const statementRows = p.statements.map((s) => ({
|
|
15952
|
+
framework_id: frameworkId,
|
|
15953
|
+
statement_id: s.id,
|
|
15954
|
+
parent_statement_id: s.parentId ?? null,
|
|
15955
|
+
grade_min: s.gradeBand[0],
|
|
15956
|
+
grade_max: s.gradeBand[1],
|
|
15957
|
+
texts: s.texts,
|
|
15958
|
+
classifications: s.classifications ?? [],
|
|
15959
|
+
bloom_hint: s.bloomHint ?? null,
|
|
15960
|
+
keywords: s.keywords ?? [],
|
|
15961
|
+
source_ref: s.sourceRef ?? null,
|
|
15962
|
+
provenance: s.provenance
|
|
15963
|
+
}));
|
|
15964
|
+
const { error: stErr, count: stCount } = await this.client.from("standards_statements").insert(statementRows, { count: "exact" });
|
|
15965
|
+
if (stErr) throw new Error("importPack: statement insert failed: " + stErr.message);
|
|
15966
|
+
let mappingCount = 0;
|
|
15967
|
+
if (p.mappings && p.mappings.length > 0) {
|
|
15968
|
+
const mappingRows = p.mappings.map((m) => ({
|
|
15969
|
+
framework_id: frameworkId,
|
|
15970
|
+
statement_id: m.statementId,
|
|
15971
|
+
target_ref: m.targetRef,
|
|
15972
|
+
kind: m.kind,
|
|
15973
|
+
confidence: m.confidence,
|
|
15974
|
+
provenance: m.provenance
|
|
15975
|
+
}));
|
|
15976
|
+
const { error: mpErr, count: mpCount } = await this.client.from("standards_mappings").insert(mappingRows, { count: "exact" });
|
|
15977
|
+
if (mpErr) throw new Error("importPack: mapping insert failed: " + mpErr.message);
|
|
15978
|
+
mappingCount = mpCount ?? mappingRows.length;
|
|
15979
|
+
}
|
|
15980
|
+
return { frameworkDbId: frameworkId, statementsInserted: stCount ?? statementRows.length, mappingsInserted: mappingCount };
|
|
15981
|
+
}
|
|
15982
|
+
/** Activate a draft framework (immutable version is now live). */
|
|
15983
|
+
async activatePack(frameworkDbId) {
|
|
15984
|
+
const { error } = await this.client.from("standards_frameworks").update({ status: "active" }).eq("id", frameworkDbId).eq("status", "draft");
|
|
15985
|
+
if (error) throw new Error("activatePack failed: " + error.message);
|
|
15986
|
+
}
|
|
15987
|
+
async deprecatePack(frameworkDbId) {
|
|
15988
|
+
const { error } = await this.client.from("standards_frameworks").update({ status: "deprecated" }).eq("id", frameworkDbId);
|
|
15989
|
+
if (error) throw new Error("deprecatePack failed: " + error.message);
|
|
15990
|
+
}
|
|
15991
|
+
async adoptPack(frameworkDbId, organizationCode, adoptedBy) {
|
|
15992
|
+
const { error } = await this.client.from("standards_org_adoptions").upsert(
|
|
15993
|
+
{ framework_id: frameworkDbId, organization_code: organizationCode, adopted_by: adoptedBy ?? null },
|
|
15994
|
+
{ onConflict: "organization_code,framework_id" }
|
|
15995
|
+
);
|
|
15996
|
+
if (error) throw new Error("adoptPack failed: " + error.message);
|
|
15997
|
+
}
|
|
15998
|
+
// ─── Runtime (read path — generation) ─────────────────────────────────────
|
|
15999
|
+
/**
|
|
16000
|
+
* Load all packs usable by an org: platform packs (verified, org IS NULL) +
|
|
16001
|
+
* org packs + org adoptions. Hydrated into the same FrameworkPack shape the
|
|
16002
|
+
* in-memory Phase-1 components consume (injector / coverage gate / judge).
|
|
16003
|
+
*/
|
|
16004
|
+
async loadPacksForOrg(organizationCode) {
|
|
16005
|
+
let query = this.client.from("standards_frameworks").select("*, standards_org_adoptions(organization_code)").eq("status", "active");
|
|
16006
|
+
const { data: frameworks, error } = await query;
|
|
16007
|
+
if (error) throw new Error("loadPacksForOrg: " + error.message);
|
|
16008
|
+
const visible = (frameworks ?? []).filter((f) => {
|
|
16009
|
+
const own = f.organization_code && organizationCode && f.organization_code === organizationCode;
|
|
16010
|
+
const global = !f.organization_code;
|
|
16011
|
+
const adopted = organizationCode && (f.standards_org_adoptions ?? []).some((a) => a.organization_code === organizationCode);
|
|
16012
|
+
return global || own || adopted;
|
|
16013
|
+
});
|
|
16014
|
+
if (visible.length === 0) return [];
|
|
16015
|
+
const ids = visible.map((f) => f.id);
|
|
16016
|
+
const [{ data: statements, error: stErr }, { data: mappings, error: mpErr }, { data: overrides, error: ovErr }] = await Promise.all([
|
|
16017
|
+
this.client.from("standards_statements").select("*").in("framework_id", ids),
|
|
16018
|
+
this.client.from("standards_mappings").select("*").in("framework_id", ids),
|
|
16019
|
+
this.client.from("standards_mapping_overrides").select("*").in("framework_id", ids)
|
|
16020
|
+
]);
|
|
16021
|
+
if (stErr) throw new Error("loadPacksForOrg statements: " + stErr.message);
|
|
16022
|
+
const overridesByFw = /* @__PURE__ */ new Map();
|
|
16023
|
+
for (const o of overrides ?? []) {
|
|
16024
|
+
const list = overridesByFw.get(o.framework_id) ?? [];
|
|
16025
|
+
list.push(o);
|
|
16026
|
+
overridesByFw.set(o.framework_id, list);
|
|
16027
|
+
}
|
|
16028
|
+
return visible.map((f) => {
|
|
16029
|
+
const stmts = (statements ?? []).filter((s) => s.framework_id === f.id).map((s) => ({
|
|
16030
|
+
id: s.statement_id,
|
|
16031
|
+
parentId: s.parent_statement_id ?? void 0,
|
|
16032
|
+
gradeBand: [s.grade_min, s.grade_max],
|
|
16033
|
+
texts: s.texts,
|
|
16034
|
+
classifications: s.classifications ?? [],
|
|
16035
|
+
bloomHint: s.bloom_hint ?? void 0,
|
|
16036
|
+
keywords: s.keywords ?? [],
|
|
16037
|
+
sourceRef: s.source_ref ?? void 0,
|
|
16038
|
+
provenance: s.provenance ?? { method: "imported" }
|
|
16039
|
+
}));
|
|
16040
|
+
const ov = overridesByFw.get(f.id) ?? [];
|
|
16041
|
+
const retired = new Set(ov.filter((o) => o.kind === "retired").map((o) => o.statement_id + "|" + o.target_ref));
|
|
16042
|
+
const embedded = (mappings ?? []).filter((m) => m.framework_id === f.id).map((m) => ({
|
|
16043
|
+
statementId: m.statement_id,
|
|
16044
|
+
targetRef: m.target_ref,
|
|
16045
|
+
kind: m.kind,
|
|
16046
|
+
confidence: Number(m.confidence),
|
|
16047
|
+
provenance: m.provenance ?? { method: "imported" }
|
|
16048
|
+
}));
|
|
16049
|
+
const overlay = ov.filter((o) => o.kind !== "retired").map((o) => ({
|
|
16050
|
+
statementId: o.statement_id,
|
|
16051
|
+
targetRef: o.target_ref,
|
|
16052
|
+
kind: o.kind,
|
|
16053
|
+
confidence: Number(o.confidence),
|
|
16054
|
+
provenance: { method: "human", reviewedBy: o.created_by ?? "overlay", note: o.note ?? void 0 }
|
|
16055
|
+
}));
|
|
16056
|
+
const bridge = /* @__PURE__ */ new Map();
|
|
16057
|
+
for (const m of embedded) bridge.set(m.statementId + "|" + m.targetRef, m);
|
|
16058
|
+
for (const m of overlay) bridge.set(m.statementId + "|" + m.targetRef, m);
|
|
16059
|
+
const finalMappings = [...bridge.values()].filter((m) => !retired.has(m.statementId + "|" + m.targetRef));
|
|
16060
|
+
const hydrated = FrameworkPackSchema.safeParse({
|
|
16061
|
+
manifest: {
|
|
16062
|
+
id: f.pack_id,
|
|
16063
|
+
name: f.name,
|
|
16064
|
+
specVersion: f.spec_version || "1.0",
|
|
16065
|
+
contentVersion: f.content_version,
|
|
16066
|
+
subject: f.subject,
|
|
16067
|
+
languages: f.languages,
|
|
16068
|
+
gradeModel: f.grade_model,
|
|
16069
|
+
provenance: f.provenance,
|
|
16070
|
+
trust: f.trust
|
|
16071
|
+
},
|
|
16072
|
+
statements: stmts,
|
|
16073
|
+
mappings: finalMappings
|
|
16074
|
+
});
|
|
16075
|
+
if (!hydrated.success) {
|
|
16076
|
+
throw new Error('loadPacksForOrg: hydrated pack "' + f.pack_id + '" failed schema: ' + hydrated.error.issues[0]?.message);
|
|
16077
|
+
}
|
|
16078
|
+
return { ...hydrated.data, dbId: f.id, status: f.status, organizationCode: f.organization_code ?? null };
|
|
16079
|
+
});
|
|
16723
16080
|
}
|
|
16724
16081
|
};
|
|
16725
16082
|
|
|
@@ -17210,6 +16567,6 @@ function renderMediaPlaceholder(entry) {
|
|
|
17210
16567
|
return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
|
|
17211
16568
|
}
|
|
17212
16569
|
|
|
17213
|
-
export { ACT_TEMPLATE, ARTIFACT_EXECUTION_ORDER, AcademicAuditor, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ArtifactContractRowSchema, AssessmentMapRowSchema, AssessmentObjectiveSchema, BELL_RINGER_TEMPLATE, BLOOM_ACTION_VERBS, BOM_TEMPLATE, BUNDLED_STANDARDS_PACK_IDS, BellRingerDaySchema, BellRingerSchema, BloomHintSchema, BloomLevelSchema, BloomTaxonomyEvaluator, BronzeTierSchema, CERConclusionSchema, CHOICE_BOARD_TEMPLATE, CODE_LAB_TEMPLATE, CURRICULUM_SLASH_COMMANDS, CardTierEnum, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquareSchema, ClassificationSchema, CodeHardwareFeasibilityEvaluator, CodeLabSchema, CodeSnippetSchema, CompetencyRubricRowSchema, ComputationalThinkingSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DependencyEdgeSchema, DepthAssignmentSchema, DepthLevelSchema, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, EXIT_TICKET_TEMPLATE, EXPOSITION_REL, EXT_TEMPLATE, EntryLevelSchema, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, ExpositionApprovalError, ExtensionChallengeSchema, ExtensionSchema, FileSystemCurriculumAdapter, FiveEFlowPhaseSchema, FiveEInstructionalEvaluator, FiveEPhaseEnum, FrameworkMappingSchema, FrameworkPackManifestSchema, FrameworkPackSchema, FrameworkStatementSchema, GLOSSARY_TEMPLATE, GRAPHIC_ORGANIZER_TEMPLATE, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HANDOUT_TEMPLATE, HandoutSchema, HandoutSectionSchema, InstructionSectionSchema, InstructionStepSchema, JudgeCriterionSchema, LAYER_TOTAL_BUDGET_MS, LESSON_PLAN_TEMPLATE, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MappingKindSchema, MarpSlideSchema, MediaError, MediaLedger, MentorCheatsheetSchema, MilestoneInputSchema, MisconceptionEvaluator, MisconceptionSchema, ModelPolicyResolver, NVIDIA_MODELS, NodeKindSchema, OrganizerTypeEnum, PROJECT_INSTRUCTION_TEMPLATE, PhaseInputSchema, PlanConstraintsSchema, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHintsSchema, ProjectGraphSchema, ProjectInstructionSchema, ProjectProfileSchema, QUIZ_TEMPLATE, QualityAuditVerdictSchema, QuizOptionSchema, REVIEW_GAME_TEMPLATE, RUBRIC_TEMPLATE, RecordProvenanceSchema, ResourceMapRowSchema, ReviewGameExportRowSchema, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInputSchema, RotationStationSchema, RubricCriteriaSchema, RubricSchema, SCIENCE_LAB_TEMPLATE, SELF_LAB_TEMPLATE, SLIDE_LAYOUT_PRESETS, SLIDE_TEMPLATE, STANDARD_SOT_FILES, STATION_ROTATION_TEMPLATE, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SilverTierSchema, SlideDeckSchema, StandardizedTermRowSchema, StandardsRegistryAdapter, StationRecordRowSchema, StationRotationSchema, StationTypeEnum, SupabaseCurriculumAdapter, TASK_CARDS_TEMPLATE, TEACHER_GUIDE_TEMPLATE, TIERED_PRACTICE_TEMPLATE, TaskCardSchema, TaskCardsSchema, TeacherGuideSchema, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntrySchema, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WORKSHEET_TEMPLATE, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, activityTools, analystTools, analyzeProjectCreationIntent,
|
|
16570
|
+
export { ACT_TEMPLATE, ARTIFACT_EXECUTION_ORDER, AcademicAuditor, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ArtifactContractRowSchema, AssessmentMapRowSchema, AssessmentObjectiveSchema, BELL_RINGER_TEMPLATE, BLOOM_ACTION_VERBS, BOM_TEMPLATE, BUNDLED_STANDARDS_PACK_IDS, BellRingerDaySchema, BellRingerSchema, BloomHintSchema, BloomLevelSchema, BloomTaxonomyEvaluator, BronzeTierSchema, CERConclusionSchema, CHOICE_BOARD_TEMPLATE, CODE_LAB_TEMPLATE, CURRICULUM_SLASH_COMMANDS, CardTierEnum, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquareSchema, ClassificationSchema, CodeHardwareFeasibilityEvaluator, CodeLabSchema, CodeSnippetSchema, CompetencyRubricRowSchema, ComputationalThinkingSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DependencyEdgeSchema, DepthAssignmentSchema, DepthLevelSchema, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, EXIT_TICKET_TEMPLATE, EXPOSITION_REL, EXT_TEMPLATE, EntryLevelSchema, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, ExpositionApprovalError, ExtensionChallengeSchema, ExtensionSchema, FileSystemCurriculumAdapter, FiveEFlowPhaseSchema, FiveEInstructionalEvaluator, FiveEPhaseEnum, FrameworkMappingSchema, FrameworkPackManifestSchema, FrameworkPackSchema, FrameworkStatementSchema, GLOSSARY_TEMPLATE, GRAPHIC_ORGANIZER_TEMPLATE, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HANDOUT_TEMPLATE, HandoutSchema, HandoutSectionSchema, InstructionSectionSchema, InstructionStepSchema, JudgeCriterionSchema, LAYER_TOTAL_BUDGET_MS, LESSON_PLAN_TEMPLATE, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MappingKindSchema, MarpSlideSchema, MediaError, MediaLedger, MentorCheatsheetSchema, MilestoneInputSchema, MisconceptionEvaluator, MisconceptionSchema, ModelPolicyResolver, NVIDIA_MODELS, NodeKindSchema, OrganizerTypeEnum, PROJECT_INSTRUCTION_TEMPLATE, PhaseInputSchema, PlanConstraintsSchema, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHintsSchema, ProjectGraphSchema, ProjectInstructionSchema, ProjectProfileSchema, QUIZ_TEMPLATE, QualityAuditVerdictSchema, QuizOptionSchema, REVIEW_GAME_TEMPLATE, RUBRIC_TEMPLATE, RecordProvenanceSchema, ResourceMapRowSchema, ReviewGameExportRowSchema, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInputSchema, RotationStationSchema, RubricCriteriaSchema, RubricSchema, SCIENCE_LAB_TEMPLATE, SELF_LAB_TEMPLATE, SLIDE_LAYOUT_PRESETS, SLIDE_TEMPLATE, STANDARD_SOT_FILES, STATION_ROTATION_TEMPLATE, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SilverTierSchema, SlideDeckSchema, StandardizedTermRowSchema, StandardsRegistryAdapter, StationRecordRowSchema, StationRotationSchema, StationTypeEnum, SupabaseCurriculumAdapter, TASK_CARDS_TEMPLATE, TEACHER_GUIDE_TEMPLATE, TIERED_PRACTICE_TEMPLATE, TaskCardSchema, TaskCardsSchema, TeacherGuideSchema, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntrySchema, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WORKSHEET_TEMPLATE, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, activityTools, analystTools, analyzeProjectCreationIntent, assertAcyclic, assessorTools, auditCurriculumQualityFlow, auditQualityReport, buildActivityPrompt, buildCodeLabPrompt, buildCurriculumContext, buildCurriculumPlan, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildExpositionContext, buildExtensionPrompt, buildHandoutPrompt, buildImagePrompt, buildJudgePrompt, buildLessonMasterPrompt, buildProjectInstructionPrompt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWorksheetPrompt, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createCurriculumStorage, createStreamAbortSignal, curateMediaLedger, designerTools, detectProjectPedagogy, ensureExpositionForLesson, ensureKnowledgeExposition, evaluateStandardsCoverage, executeCurriculumCommand, exportAllProjectQuizzes, expositionCacheKey, extractScopeSequenceRows, extractSessionSlice, extractStreamChunk, extractThoughtAndContent, formatQuizzesToCsv, fulfillMediaLedger, gateModeFor, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateEducationalImage, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateMilestoneCurriculumBundle, generatePhase1SotArtifacts, generatePhase2SotArtifacts, generateProjectInstruction, generateProjectInstructionFlow, generateRoadmapCurriculum, generateSelfLabFlow, generateSelfPacedBundle, generateSingleArtifact, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, getAIModel, getArtifactMetadata, getDesignatedFallbackChain, getDesignatedFallbackConfig, getLessonMetadata, getProjectArtifactScope, getProjectStatusReport, getSlideLayoutPresetById, getSlideLayoutPresetsByCategory, getSmartResumeContext, glossaryTermsForSession, illustratorTools, importRoadmapToProject, ingestProjectGraphIntoProject, initializeProjectInStorage, injectMediaIntoMarkdown, isExpositionFresh, isModelAllowed, isProviderEnabled, isTranslationDue, lintAndSanitizeArtifact, lintCurriculumFramework, lintFrameworkPack, loadCurriculumTemplate, loadSotTemplate, normalizePlanningGraph, packagerTools, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderFrameworkFromPlan, renderMediaPlaceholder, researcherTools, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, techSmeTools, topoSort, uploadAssetToBucket, validateCurriculumPlan, validateFrameworkPack, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
|
|
17214
16571
|
//# sourceMappingURL=index.mjs.map
|
|
17215
16572
|
//# sourceMappingURL=index.mjs.map
|