@thanh01.pmt/curriculum-kit 1.2.0 → 1.2.1

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/index.mjs CHANGED
@@ -5560,13 +5560,13 @@ Evaluate the candidate artifact across these 6 dimensions:
5560
5560
  - 0 pts: Missing critical sections.
5561
5561
 
5562
5562
  5. **Technical & Conceptual Accuracy (15 pts):**
5563
- - 15 pts: Code snippets, logic flows, architectural descriptions, and Mermaid diagrams are conceptually sound, valid, and free of syntax hallucinations.
5563
+ - 15 pts: Code snippets, logic flows, architectural descriptions, and Mermaid diagrams are conceptually sound and valid. If \`canonicalExposition\` or \`[KNOWLEDGE_EXPOSITION]\` is provided, content strictly adheres to canonical concepts without contradicting definitions or examples.
5564
5564
  - 8 pts: Minor syntax inaccuracies or unidiomatic code that does not break core concepts.
5565
- - 0 pts: Severe technical hallucinations, broken logic, or invalid diagrams.
5565
+ - 0 pts: Severe technical hallucinations, broken logic, invalid diagrams, or direct contradiction of canonical exposition knowledge.
5566
5566
 
5567
5567
  6. **Contract Consistency & Zero-Drift (10 pts):**
5568
- - 10 pts: Satellite artifact strictly adheres to the scope, tech stack, and objectives of Lesson ${lessonId} without introducing unrelated topics.
5569
- - 0-5 pts: Scope drift or topic divergence detected.
5568
+ - 10 pts: Satellite artifact strictly adheres to the scope, tech stack, and objectives of Lesson ${lessonId} without introducing unrelated topics. If \`canonicalLessonExcerpt\` is present in candidate JSON, all satellite phases/activities strictly operationalize the master Lesson Flow and Activity Sequence without inventing divergent timelines.
5569
+ - 0-5 pts: Scope drift, topic divergence, or disjoint activity sequence detected compared to master lesson.
5570
5570
 
5571
5571
  ## VERDICT RULES
5572
5572
  - **PASS:** Score >= 80 AND Language Adherence = true AND Standards Alignment >= 12 (when STANDARDS GROUND TRUTH is present).
@@ -11861,11 +11861,42 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
11861
11861
  }
11862
11862
  const pedagogy = detectProjectPedagogy(framework, styleGuide, options.pedagogy);
11863
11863
  const pedagogyLabel = pedagogy.toUpperCase();
11864
- const styleGuideExcerpt = styleGuide ? buildSectionAwareExcerpt(styleGuide, {
11864
+ let glossaryContext = "";
11865
+ try {
11866
+ const glossaryRaw = await storage.readArtifact(projectId, "_sot/GLOSSARY.json");
11867
+ if (glossaryRaw) {
11868
+ let allTerms = [];
11869
+ try {
11870
+ allTerms = JSON.parse(glossaryRaw).terms ?? [];
11871
+ } catch {
11872
+ }
11873
+ let scopedTermsSet = null;
11874
+ const planRaw = await storage.readArtifact(projectId, "_sot/CURRICULUM_PLAN.json");
11875
+ if (planRaw) {
11876
+ try {
11877
+ const plan = JSON.parse(planRaw);
11878
+ const sessionScope = plan.glossary_scope?.find((g) => g.session_id === lessonCode);
11879
+ if (sessionScope?.terms?.length) {
11880
+ scopedTermsSet = new Set(sessionScope.terms.map((t) => t.toLowerCase()));
11881
+ }
11882
+ } catch {
11883
+ }
11884
+ }
11885
+ const relevantTerms = scopedTermsSet ? allTerms.filter((g) => scopedTermsSet.has(g.term.toLowerCase())) : allTerms.slice(0, 10);
11886
+ if (relevantTerms.length > 0) {
11887
+ const lines = relevantTerms.map(
11888
+ (t) => `- **${t.term}**: ${t.definition || ""}${t.example ? ` (e.g. \`${t.example}\`)` : ""}`
11889
+ );
11890
+ glossaryContext = buildSectionAwareExcerpt(lines.join("\n"), { budget: 800 }).excerpt;
11891
+ }
11892
+ }
11893
+ } catch {
11894
+ }
11895
+ let effectiveStyleGuide = styleGuide ? buildSectionAwareExcerpt(styleGuide, {
11865
11896
  priorities: ["Voice & Tone", "Standard Terminology (Glossary)", "Lesson Content Standards"],
11866
11897
  budget: 2e3
11867
11898
  }).excerpt : "";
11868
- const refPackExcerpt = refPack ? buildSectionAwareExcerpt(refPack, {
11899
+ let effectiveRefPack = refPack ? buildSectionAwareExcerpt(refPack, {
11869
11900
  priorities: [
11870
11901
  "Technical Overview & Architecture Blueprint",
11871
11902
  "Hardware Pinout & Wiring Configuration Matrix",
@@ -11873,7 +11904,7 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
11873
11904
  ],
11874
11905
  budget: 2500
11875
11906
  }).excerpt : "";
11876
- const commonContext = `PROJECT & ACADEMIC CONTEXT:
11907
+ const baseContextPrefix = `PROJECT & ACADEMIC CONTEXT:
11877
11908
  - Project ID: ${projectId}
11878
11909
  - Pedagogical Model: ${pedagogyLabel}
11879
11910
  - Lesson Code: ${lessonCode}
@@ -11883,13 +11914,51 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
11883
11914
  - Target Bloom Level: ${bloomLevel}
11884
11915
 
11885
11916
  [CURRICULUM FRAMEWORK EXCERPT]:
11886
- ${buildFrameworkExcerptForLesson(framework, lessonId)}
11917
+ ${buildFrameworkExcerptForLesson(framework, lessonId)}`;
11918
+ const glossaryBlock = glossaryContext ? `
11919
+
11920
+ [GLOSSARY TERMS (use these exact definitions)]:
11921
+ ${glossaryContext}` : "";
11922
+ const standardsBlock = standardsContext ? `
11923
+
11924
+ ${standardsContext}` : "";
11925
+ const expositionBlock = expositionContext ? `
11926
+
11927
+ [KNOWLEDGE_EXPOSITION (CANONICAL KNOWLEDGE \u2014 teach from this, do not contradict)]:
11928
+ ${expositionContext}` : "";
11929
+ const sessionSliceBlock = sessionSliceContext ? `
11930
+
11931
+ ${sessionSliceContext}` : "";
11932
+ const assembleCommonContext = (ref, sg) => `${baseContextPrefix}
11887
11933
 
11888
11934
  [CONTENT STYLE GUIDE EXCERPT]:
11889
- ${styleGuideExcerpt}
11935
+ ${sg}
11890
11936
 
11891
11937
  [REFERENCE PACK GROUND TRUTH]:
11892
- ${refPackExcerpt}${standardsContext ? "\n\n" + standardsContext : ""}${expositionContext ? "\n\n[KNOWLEDGE_EXPOSITION (CANONICAL KNOWLEDGE \u2014 teach from this, do not contradict)]:\n" + expositionContext : ""}${sessionSliceContext ? "\n\n" + sessionSliceContext : ""}`;
11938
+ ${ref}${standardsBlock}${glossaryBlock}${expositionBlock}${sessionSliceBlock}`;
11939
+ let commonContext = assembleCommonContext(effectiveRefPack, effectiveStyleGuide);
11940
+ const MAX_COMPOSITE_PROMPT_CHARS = 3e4;
11941
+ if (commonContext.length > MAX_COMPOSITE_PROMPT_CHARS && effectiveRefPack.length > 1e3) {
11942
+ effectiveRefPack = buildSectionAwareExcerpt(refPack, {
11943
+ priorities: [
11944
+ "Technical Overview & Architecture Blueprint",
11945
+ "Hardware Pinout & Wiring Configuration Matrix"
11946
+ ],
11947
+ budget: 1e3
11948
+ }).excerpt;
11949
+ commonContext = assembleCommonContext(effectiveRefPack, effectiveStyleGuide);
11950
+ }
11951
+ if (commonContext.length > MAX_COMPOSITE_PROMPT_CHARS && effectiveStyleGuide.length > 1e3) {
11952
+ effectiveStyleGuide = buildSectionAwareExcerpt(styleGuide, {
11953
+ priorities: ["Voice & Tone", "Standard Terminology (Glossary)"],
11954
+ budget: 1e3
11955
+ }).excerpt;
11956
+ commonContext = assembleCommonContext(effectiveRefPack, effectiveStyleGuide);
11957
+ }
11958
+ onProgress?.("@content", `[CONTEXT] Composite prompt ready (${commonContext.length} chars, adaptive budget <= ${MAX_COMPOSITE_PROMPT_CHARS})`, {
11959
+ type: "progress",
11960
+ promptChars: commonContext.length
11961
+ });
11893
11962
  const producedArtifacts = [];
11894
11963
  const lessonRelPath = `_content/${unitCode}/LESSON_${lessonCode}.md`;
11895
11964
  const existingLessonContent = await storage.readArtifact(projectId, lessonRelPath);
@@ -12016,7 +12085,7 @@ ${yamlBlock.trim()}
12016
12085
  lessonId: lessonCode,
12017
12086
  title: lessonTitle,
12018
12087
  frameworkExcerpt: framework ? buildFrameworkExcerptForLesson(framework, lessonId) : void 0,
12019
- styleGuideExcerpt: styleGuideExcerpt || void 0,
12088
+ styleGuideExcerpt: effectiveStyleGuide || void 0,
12020
12089
  canonicalExposition: expositionContext ? expositionContext.slice(0, 3e3) : void 0
12021
12090
  }),
12022
12091
  standardStatements: Object.keys(standardStatements).length > 0 ? standardStatements : void 0
@@ -12059,7 +12128,7 @@ ${yamlBlock.trim()}
12059
12128
  onProgress?.("@repair", `\u{1F527} Repair round ${round}/${MAX_REPAIR_ROUNDS} for LESSON_${lessonCode} (judge score ${currentResult.score}/100)...`);
12060
12129
  const repairedRaw = await runCurriculumAIInference(
12061
12130
  [{ role: "user", content: `You previously authored \`LESSON_${lessonCode}.md\` and the academic Judge REJECTED it with the critique below.
12062
- Rewrite the COMPLETE corrected document: fix every listed issue, keep the mandatory structure, frontmatter and all approved sections. Output 100% clean Markdown only.
12131
+ Rewrite the COMPLETE corrected document in language "${targetLang}": fix every listed issue, preserve exact frontmatter and mandatory sections (Objectives, Activity Sequence, Lesson Flow). Output 100% clean Markdown only.
12063
12132
 
12064
12133
  JUDGE CRITIQUE:
12065
12134
  ${repairFeedback}
@@ -12077,7 +12146,13 @@ ${currentContent}` }],
12077
12146
  break;
12078
12147
  }
12079
12148
  const repairLint = lintAndSanitizeArtifact(repairedRaw, `LESSON_${lessonCode}.md`);
12080
- currentContent = repairLint.autoFixedContent || repairedRaw;
12149
+ const candidateContent = repairLint.autoFixedContent || repairedRaw;
12150
+ const hasFrontmatter = /^---\s*\r?\n[\s\S]*?\r?\n---/m.test(candidateContent);
12151
+ if (!hasFrontmatter || candidateContent.length < Math.min(800, currentContent.length * 0.4)) {
12152
+ onProgress?.("@repair", `\u26A0\uFE0F Repair round ${round} dropped critical structure (length or frontmatter missing) \u2014 rejecting repaired draft, retaining previous`);
12153
+ break;
12154
+ }
12155
+ currentContent = candidateContent;
12081
12156
  onProgress?.("@reviewer", `\u{1F916} Re-judging repaired LESSON_${lessonCode} (round ${round})...`);
12082
12157
  const reJudge = await LLMJudgeEngine.evaluateArtifactWithLLM({
12083
12158
  targetArtifactType: "LESSON",
@@ -12089,7 +12164,7 @@ ${currentContent}` }],
12089
12164
  lessonId: lessonCode,
12090
12165
  title: lessonTitle,
12091
12166
  frameworkExcerpt: framework ? buildFrameworkExcerptForLesson(framework, lessonId) : void 0,
12092
- styleGuideExcerpt: styleGuideExcerpt || void 0,
12167
+ styleGuideExcerpt: effectiveStyleGuide || void 0,
12093
12168
  canonicalExposition: expositionContext ? expositionContext.slice(0, 3e3) : void 0
12094
12169
  }),
12095
12170
  standardStatements: Object.keys(standardStatements).length > 0 ? standardStatements : void 0