@thanh01.pmt/curriculum-kit 1.4.34 → 1.4.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ai/index.cjs +57 -1
  3. package/dist/ai/index.cjs.map +1 -1
  4. package/dist/ai/index.d.cts +2 -2
  5. package/dist/ai/index.d.ts +2 -2
  6. package/dist/ai/index.mjs +57 -1
  7. package/dist/ai/index.mjs.map +1 -1
  8. package/dist/{gateSettings-DabOqP6_.d.cts → gateSettings-oo5tCUS_.d.cts} +18 -0
  9. package/dist/{gateSettings-DabOqP6_.d.ts → gateSettings-oo5tCUS_.d.ts} +18 -0
  10. package/dist/index.cjs +764 -70
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +234 -74
  13. package/dist/index.d.ts +234 -74
  14. package/dist/index.mjs +748 -71
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/pipeline/index.cjs +57 -1
  17. package/dist/pipeline/index.cjs.map +1 -1
  18. package/dist/pipeline/index.mjs +57 -1
  19. package/dist/pipeline/index.mjs.map +1 -1
  20. package/dist/schemas/index.cjs +63 -1
  21. package/dist/schemas/index.cjs.map +1 -1
  22. package/dist/schemas/index.d.cts +436 -33
  23. package/dist/schemas/index.d.ts +436 -33
  24. package/dist/schemas/index.mjs +58 -2
  25. package/dist/schemas/index.mjs.map +1 -1
  26. package/dist/standards/index.d.cts +2 -2
  27. package/dist/standards/index.d.ts +2 -2
  28. package/dist/workflow/index.cjs +84 -2
  29. package/dist/workflow/index.cjs.map +1 -1
  30. package/dist/workflow/index.d.cts +3 -3
  31. package/dist/workflow/index.d.ts +3 -3
  32. package/dist/workflow/index.mjs +84 -2
  33. package/dist/workflow/index.mjs.map +1 -1
  34. package/package.json +22 -23
  35. package/dist/{standardsCoverageGate-DR5YTtlt.d.cts → standardsCoverageGate-49pJq5t8.d.cts} +6 -6
  36. package/dist/{standardsCoverageGate-DR5YTtlt.d.ts → standardsCoverageGate-49pJq5t8.d.ts} +6 -6
package/dist/index.mjs CHANGED
@@ -3562,6 +3562,50 @@ var ScaffoldDecisionEntrySchema = z.object({
3562
3562
  minutes_saved: z.number().int().nonnegative().default(0),
3563
3563
  reason: z.string().min(3)
3564
3564
  });
3565
+ var ZpdVerdictSchema = z.enum(["OK", "TOO_MANY_NEW", "NO_ZPD_BRIDGE"]);
3566
+ var SessionZpdStatusSchema = z.object({
3567
+ verdict: ZpdVerdictSchema,
3568
+ new_concept_count: z.number().int().nonnegative().default(0),
3569
+ known_concept_count: z.number().int().nonnegative().default(0),
3570
+ issues: z.array(z.string()).default([])
3571
+ });
3572
+ var ConceptSpiralEncounterSchema = z.object({
3573
+ concept_code: z.string(),
3574
+ session_id: LessonCodeSchema,
3575
+ encounter_index: z.number().int().positive(),
3576
+ bloom_cap: BloomLevelSchema,
3577
+ depth: DepthLevelSchema
3578
+ });
3579
+ var WalkingSkeletonSchema = z.object({
3580
+ epitome_unit_id: z.string().default("U01"),
3581
+ epitome_deliverables: z.array(z.string()).default([]),
3582
+ elaborations: z.array(z.object({
3583
+ unit_id: z.string(),
3584
+ focus_area: z.string(),
3585
+ elaborates_on: z.array(z.string()).default([])
3586
+ })).default([])
3587
+ });
3588
+ var MasteryGateSchema = z.object({
3589
+ phase_or_unit_id: z.string(),
3590
+ gate_name: z.string(),
3591
+ exit_criteria: z.array(z.string()).min(1),
3592
+ next_unit_id: z.string(),
3593
+ remediation: z.object({
3594
+ trigger: z.literal("FAIL_GATE_CRITERIA"),
3595
+ focus_minutes: z.number().int().default(15),
3596
+ action: z.string()
3597
+ })
3598
+ });
3599
+ var ConceptPrerequisiteEdgeSchema = z.object({
3600
+ concept_code: z.string(),
3601
+ requires: z.string(),
3602
+ source: z.enum(["MASTER_TREE", "INFERRED", "CONCEPT_LEVEL_PREREQ"]).default("CONCEPT_LEVEL_PREREQ"),
3603
+ confidence: z.number().min(0).max(1).default(0.8),
3604
+ rationale: z.string().default(""),
3605
+ structure_supported: z.boolean().default(true),
3606
+ needs_review: z.boolean().default(false),
3607
+ hub: z.boolean().default(false)
3608
+ });
3565
3609
  var SessionPlanSchema = z.object({
3566
3610
  id: LessonCodeSchema,
3567
3611
  unit_id: z.string().regex(/^U\d{2}$/),
@@ -3582,7 +3626,14 @@ var SessionPlanSchema = z.object({
3582
3626
  scaffold_decisions: z.array(ScaffoldDecisionEntrySchema).default([]),
3583
3627
  // What the student can demonstrate after this session — feeds exit tickets.
3584
3628
  exit_evidence: z.array(z.string()).min(1),
3585
- differentiation: z.object({ bronze: z.string(), silver: z.string(), gold: z.string() })
3629
+ differentiation: z.object({ bronze: z.string(), silver: z.string(), gold: z.string() }),
3630
+ // P50: ZPD cognitive load status for this session
3631
+ zpd_status: SessionZpdStatusSchema.default({
3632
+ verdict: "OK",
3633
+ new_concept_count: 0,
3634
+ known_concept_count: 0,
3635
+ issues: []
3636
+ })
3586
3637
  });
3587
3638
  var TranslationPolicySchema = z.object({
3588
3639
  policy: z.enum(["after_artifact", "end_of_unit", "at_publish", "native"]).default("native"),
@@ -3637,6 +3688,11 @@ var CurriculumPlanSchema = z.object({
3637
3688
  // [2]
3638
3689
  sessions: z.array(SessionPlanSchema).min(1),
3639
3690
  // [3][4][5][6]
3691
+ // P50: Macro-pedagogical course structures
3692
+ walking_skeleton: WalkingSkeletonSchema.optional(),
3693
+ mastery_gates: z.array(MasteryGateSchema).default([]),
3694
+ concept_spiral_progression: z.array(ConceptSpiralEncounterSchema).default([]),
3695
+ concept_prerequisites: z.array(ConceptPrerequisiteEdgeSchema).default([]),
3640
3696
  glossary_scope: z.array(z.object({
3641
3697
  session_id: LessonCodeSchema,
3642
3698
  terms: z.array(z.string())
@@ -11267,7 +11323,8 @@ function parseAllSessions(plan, frameworkMarkdown) {
11267
11323
  prose_objective: s.prose_objective || s.objective || "",
11268
11324
  new_keywords: Array.isArray(s.new_keywords) ? s.new_keywords : Array.isArray(s.keywords) ? s.keywords : [],
11269
11325
  prerequisite_keywords: Array.isArray(s.prerequisite_keywords) ? s.prerequisite_keywords : [],
11270
- depth_assignments: Array.isArray(s.depth_assignments) ? s.depth_assignments : []
11326
+ depth_assignments: Array.isArray(s.depth_assignments) ? s.depth_assignments : [],
11327
+ zpd_status: s.zpd_status
11271
11328
  }));
11272
11329
  }
11273
11330
  }
@@ -11415,12 +11472,16 @@ async function extractCurriculumHorizon(opts) {
11415
11472
  title: s.title,
11416
11473
  keywords: s.new_keywords || []
11417
11474
  }));
11475
+ const rawSpirals = Array.isArray(plan?.concept_spiral_progression) ? plan.concept_spiral_progression : [];
11476
+ const sessionSpirals = rawSpirals.filter((e) => e.session_id === targetLessonId);
11418
11477
  return {
11419
11478
  targetLessonId,
11420
11479
  targetLessonIndex: targetIndex + 1,
11421
11480
  totalLessons: sessions.length,
11422
11481
  targetTitle: currentSession.title,
11423
11482
  targetKeywords: currentSession.new_keywords || [],
11483
+ zpdStatus: currentSession.zpd_status,
11484
+ spiralProgression: sessionSpirals,
11424
11485
  compactMasterySet: {
11425
11486
  masteredKeywords,
11426
11487
  masteredConcepts
@@ -11436,6 +11497,8 @@ function renderHorizonPromptBlock(horizon) {
11436
11497
  totalLessons,
11437
11498
  targetTitle,
11438
11499
  targetKeywords,
11500
+ zpdStatus,
11501
+ spiralProgression,
11439
11502
  compactMasterySet,
11440
11503
  detailedBridge,
11441
11504
  boundaryPeek
@@ -11443,6 +11506,19 @@ function renderHorizonPromptBlock(horizon) {
11443
11506
  const lines = [
11444
11507
  `# \u{1F9ED} CURRICULUM HORIZON & SCAFFOLDING MATRIX (Lesson ${targetLessonIndex}/${totalLessons}: "${targetTitle}" [${targetLessonId}])`
11445
11508
  ];
11509
+ if (zpdStatus && zpdStatus.verdict !== "OK") {
11510
+ lines.push(
11511
+ `
11512
+ > \u26A0\uFE0F **ZPD COGNITIVE LOAD ALERT (${zpdStatus.verdict}):** ${zpdStatus.issues?.join("; ") || "Scaffolding bridge mandated"}. Introduce minimal new syntax and anchor into known concepts.`
11513
+ );
11514
+ }
11515
+ if (spiralProgression && spiralProgression.length > 0) {
11516
+ const spiralNotes = spiralProgression.map(
11517
+ (sp) => `\`${sp.concept_code}\` (Encounter #${sp.encounter_index}): Bloom Cap [${sp.bloom_cap}], Depth [${sp.depth.toUpperCase()}]`
11518
+ );
11519
+ lines.push(`
11520
+ - **\u{1F300} Bruner Spiral Curricula Guidance:** ${spiralNotes.join(" | ")}`);
11521
+ }
11446
11522
  if (compactMasterySet.masteredKeywords.length > 0 || compactMasterySet.masteredConcepts.length > 0) {
11447
11523
  const rawKeywords = compactMasterySet.masteredKeywords;
11448
11524
  const displayedKeywords = rawKeywords.length > 20 ? rawKeywords.slice(-20) : rawKeywords;
@@ -11613,9 +11689,9 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
11613
11689
  if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
11614
11690
  byCanonical.set(s.canonicalKey, s);
11615
11691
  }
11616
- const norm = normalizeHeading(s.cleanTitle);
11617
- if (!byCleanTitle.has(norm)) {
11618
- byCleanTitle.set(norm, s);
11692
+ const norm2 = normalizeHeading(s.cleanTitle);
11693
+ if (!byCleanTitle.has(norm2)) {
11694
+ byCleanTitle.set(norm2, s);
11619
11695
  }
11620
11696
  if (!s.canonicalKey) {
11621
11697
  unmatched.push(s);
@@ -11753,8 +11829,8 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
11753
11829
  const flush = () => {
11754
11830
  if (!currentHeading) return;
11755
11831
  const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
11756
- const norm = normalizeHeading(cleanTitle);
11757
- const canonicalKey = reverseMap.get(norm) || findCanonicalFuzzy(norm);
11832
+ const norm2 = normalizeHeading(cleanTitle);
11833
+ const canonicalKey = reverseMap.get(norm2) || findCanonicalFuzzy(norm2);
11758
11834
  sections.push({
11759
11835
  rawHeading: currentHeading,
11760
11836
  cleanTitle,
@@ -11780,49 +11856,55 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
11780
11856
  function normalizeHeading(str) {
11781
11857
  return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
11782
11858
  }
11783
- function findCanonicalFuzzy(norm) {
11784
- if (norm.includes("toolchain") || norm.includes("moi truong phat trien") || norm.includes("cong cu") || norm.includes("version") || norm.includes("phan mem") || norm.includes("development environment") || norm.includes("technical overview") || norm.includes("kien truc")) {
11859
+ function findCanonicalFuzzy(norm2) {
11860
+ if (norm2.includes("toolchain") || norm2.includes("moi truong phat trien") || norm2.includes("cong cu") || norm2.includes("version") || norm2.includes("phan mem") || norm2.includes("development environment") || norm2.includes("technical overview") || norm2.includes("kien truc")) {
11785
11861
  return "Technical Overview & Architecture Blueprint";
11786
11862
  }
11787
- if (norm.includes("pinout") || norm.includes("phan cung") || norm.includes("hardware") || norm.includes("wiring") || norm.includes("ket noi")) {
11863
+ if (norm2.includes("pinout") || norm2.includes("phan cung") || norm2.includes("hardware") || norm2.includes("wiring") || norm2.includes("ket noi")) {
11788
11864
  return "Hardware Pinout & Wiring Configuration Matrix";
11789
11865
  }
11790
- if (norm.includes("pedagog") || norm.includes("phuong phap") || norm.includes("day hoc") || norm.includes("su pham")) {
11866
+ if (norm2.includes("pedagog") || norm2.includes("phuong phap") || norm2.includes("day hoc") || norm2.includes("su pham")) {
11791
11867
  return "Core Pedagogical Concept Anchor & Real-World Domain Bridge";
11792
11868
  }
11793
- if (norm.includes("standard") || norm.includes("tieu chuan") || norm.includes("csta") || norm.includes("cs2023") || norm.includes("chuan academic")) {
11869
+ if (norm2.includes("standard") || norm2.includes("tieu chuan") || norm2.includes("csta") || norm2.includes("cs2023") || norm2.includes("chuan academic")) {
11794
11870
  return "Standards Alignment";
11795
11871
  }
11796
- if (norm.includes("roadmap") || norm.includes("lo trinh") || norm.includes("milestone") || norm.includes("giai doan")) {
11872
+ if (norm2.includes("roadmap") || norm2.includes("lo trinh") || norm2.includes("milestone") || norm2.includes("giai doan")) {
11797
11873
  return void 0;
11798
11874
  }
11799
- if (norm.includes("symbol") || norm.includes("identifier ledger") || norm.includes("dinh danh")) {
11875
+ if (norm2.includes("symbol") || norm2.includes("identifier ledger") || norm2.includes("dinh danh")) {
11800
11876
  return "Symbol & Identifier Ledger";
11801
11877
  }
11802
- if (norm.includes("artifact contract") || norm.includes("hop dong hoc lieu")) {
11878
+ if (norm2.includes("artifact contract") || norm2.includes("hop dong hoc lieu")) {
11803
11879
  return "Artifact Contract";
11804
11880
  }
11805
- if (norm.includes("lesson design plan") || norm.includes("ke hoach thiet ke")) {
11881
+ if (norm2.includes("lesson design plan") || norm2.includes("ke hoach thiet ke")) {
11806
11882
  return "A. Lesson Design Plan";
11807
11883
  }
11808
- if (norm.includes("lesson flow") || norm.includes("tien trinh giang day")) {
11884
+ if (norm2.includes("lesson flow") || norm2.includes("tien trinh giang day")) {
11809
11885
  return "B. Lesson Flow";
11810
11886
  }
11811
- if (norm.includes("learning objective") || norm.includes("muc tieu bai hoc")) {
11887
+ if (norm2.includes("learning objective") || norm2.includes("muc tieu bai hoc")) {
11812
11888
  return "Learning Objectives & Evidence";
11813
11889
  }
11814
- if (norm.includes("activity sequence") || norm.includes("chuoi hoat dong")) {
11890
+ if (norm2.includes("activity sequence") || norm2.includes("chuoi hoat dong")) {
11815
11891
  return "Activity Sequence";
11816
11892
  }
11817
- if (norm.includes("key term") || norm.includes("thuat ngu")) {
11893
+ if (norm2.includes("key term") || norm2.includes("thuat ngu")) {
11818
11894
  return "Key Terms";
11819
11895
  }
11820
- if (norm.includes("concept narrative") || norm.includes("dien giai khai niem")) {
11896
+ if (norm2.includes("concept narrative") || norm2.includes("dien giai khai niem")) {
11821
11897
  return "Concept Narratives";
11822
11898
  }
11823
- if (norm.includes("worked example") || norm.includes("vi du")) {
11899
+ if (norm2.includes("worked example") || norm2.includes("vi du")) {
11824
11900
  return "Worked Micro-Examples";
11825
11901
  }
11902
+ if (norm2.includes("common mistake") || norm2.includes("loi thuong gap") || norm2.includes("sai lam") || norm2.includes("pitfall")) {
11903
+ return "Common Mistakes";
11904
+ }
11905
+ if (norm2.includes("self check") || norm2.includes("self-check") || norm2.includes("tu kiem tra")) {
11906
+ return "Self-Check Questions";
11907
+ }
11826
11908
  return void 0;
11827
11909
  }
11828
11910
  function truncateByBudget(source, budget) {
@@ -12757,7 +12839,7 @@ function decideScaffolds(session, nodeById, warnings) {
12757
12839
  return decisions;
12758
12840
  }
12759
12841
  var DEPTH_NEXT = { ulo: "cio", cio: "sio", sio: "sio" };
12760
- function assignDepths(nodeIds, nodeById) {
12842
+ function assignDepths(nodeIds, nodeById, conceptEncounterMap) {
12761
12843
  const assignments = [];
12762
12844
  let lastDepth = null;
12763
12845
  for (const id of nodeIds) {
@@ -12765,8 +12847,14 @@ function assignDepths(nodeIds, nodeById) {
12765
12847
  let depth;
12766
12848
  let source;
12767
12849
  if (node.kind === "concept") {
12850
+ const primaryCode = node.concept_codes[0];
12851
+ const encounters = primaryCode && conceptEncounterMap ? conceptEncounterMap.get(primaryCode) ?? 1 : 1;
12768
12852
  const advanced = node.phase_id !== "" && /__ADV\d{2}$/.test(node.id);
12769
- depth = advanced ? "sio" : "cio";
12853
+ if (encounters >= 2 || advanced) {
12854
+ depth = "sio";
12855
+ } else {
12856
+ depth = "cio";
12857
+ }
12770
12858
  source = "planner";
12771
12859
  } else {
12772
12860
  depth = node.depth_hint ?? "cio";
@@ -12781,6 +12869,201 @@ function assignDepths(nodeIds, nodeById) {
12781
12869
  }
12782
12870
  return assignments;
12783
12871
  }
12872
+ function computeConceptSpiralProgression(sessions, nodeById) {
12873
+ const encounters = [];
12874
+ const conceptCounts = /* @__PURE__ */ new Map();
12875
+ for (const s of sessions) {
12876
+ const sessionConcepts = [...new Set(s.node_ids.flatMap((id) => nodeById.get(id)?.concept_codes || []))];
12877
+ for (const cCode of sessionConcepts) {
12878
+ const count = (conceptCounts.get(cCode) || 0) + 1;
12879
+ conceptCounts.set(cCode, count);
12880
+ let bloomCap;
12881
+ let depth;
12882
+ if (count === 1) {
12883
+ bloomCap = "Understand";
12884
+ depth = "cio";
12885
+ } else if (count === 2) {
12886
+ bloomCap = "Apply";
12887
+ depth = "sio";
12888
+ } else {
12889
+ bloomCap = "Analyze";
12890
+ depth = "sio";
12891
+ }
12892
+ encounters.push({
12893
+ concept_code: cCode,
12894
+ session_id: s.id,
12895
+ encounter_index: count,
12896
+ bloom_cap: bloomCap,
12897
+ depth
12898
+ });
12899
+ }
12900
+ }
12901
+ return encounters;
12902
+ }
12903
+ function checkSessionZpd(sessionIndex, nodeIds, nodeById, allSeenConcepts, allSeenKeywords, entryKw, warnings) {
12904
+ const concepts = [...new Set(nodeIds.flatMap((id) => nodeById.get(id)?.concept_codes || []))];
12905
+ const newConcepts = concepts.filter((c) => !allSeenConcepts.has(c));
12906
+ const knownConcepts = concepts.filter((c) => allSeenConcepts.has(c));
12907
+ const allKeywords = [...new Set(nodeIds.flatMap((id) => nodeById.get(id)?.keywords || []))];
12908
+ const newKeywords = allKeywords.filter((k) => !allSeenKeywords.has(k.toLowerCase()) && !entryKw.has(k.toLowerCase()));
12909
+ const knownKeywords = allKeywords.filter((k) => allSeenKeywords.has(k.toLowerCase()) || entryKw.has(k.toLowerCase()));
12910
+ const issues = [];
12911
+ let verdict = "OK";
12912
+ if (concepts.length > 0 && newConcepts.length > 2) {
12913
+ verdict = "TOO_MANY_NEW";
12914
+ issues.push(`${newConcepts.length} new concepts exceed ZPD limit (max 2)`);
12915
+ } else if (concepts.length === 0 && newKeywords.length > 4) {
12916
+ verdict = "TOO_MANY_NEW";
12917
+ issues.push(`${newKeywords.length} new keywords exceed ZPD limit (max 4)`);
12918
+ }
12919
+ if (sessionIndex > 0) {
12920
+ if (concepts.length > 1 && knownConcepts.length === 0) {
12921
+ verdict = "NO_ZPD_BRIDGE";
12922
+ issues.push("No known concepts from previous sessions to bridge new learning");
12923
+ } else if (concepts.length === 0 && allKeywords.length > 2 && knownKeywords.length === 0) {
12924
+ verdict = "NO_ZPD_BRIDGE";
12925
+ issues.push("No known keywords from previous sessions to bridge new learning");
12926
+ }
12927
+ }
12928
+ let bridgeRepair;
12929
+ if (verdict === "NO_ZPD_BRIDGE" && (allSeenConcepts.size > 0 || allSeenKeywords.size > 0)) {
12930
+ const bridgeAnchor = [...allSeenConcepts].pop() || [...allSeenKeywords].pop() || "prior knowledge";
12931
+ bridgeRepair = {
12932
+ node_id: nodeIds[0],
12933
+ decision: "recap_in_lesson",
12934
+ reason: `ZPD self-healing: recap anchor (${bridgeAnchor}) to bridge into new material`
12935
+ };
12936
+ warnings.push(`ZPD bridge self-healing: session ${sessionIndex + 1} injected recap anchor (${bridgeAnchor})`);
12937
+ }
12938
+ for (const c of concepts) allSeenConcepts.add(c);
12939
+ for (const k of allKeywords) allSeenKeywords.add(k.toLowerCase());
12940
+ return {
12941
+ status: {
12942
+ verdict,
12943
+ new_concept_count: concepts.length > 0 ? newConcepts.length : newKeywords.length,
12944
+ known_concept_count: concepts.length > 0 ? knownConcepts.length : knownKeywords.length,
12945
+ issues
12946
+ },
12947
+ bridgeRepair
12948
+ };
12949
+ }
12950
+ function buildWalkingSkeleton(units, sessions) {
12951
+ const epitomeUnit = units[0];
12952
+ const epitomeId = epitomeUnit?.id || "U01";
12953
+ const epitomeDeliverables = sessions.filter((s) => s.unit_id === epitomeId).flatMap((s) => s.exit_evidence || []).slice(0, 8);
12954
+ const elaborations = units.slice(1).map((u) => ({
12955
+ unit_id: u.id,
12956
+ focus_area: u.name,
12957
+ elaborates_on: epitomeDeliverables.slice(0, 3)
12958
+ }));
12959
+ return {
12960
+ epitome_unit_id: epitomeId,
12961
+ epitome_deliverables: epitomeDeliverables,
12962
+ elaborations
12963
+ };
12964
+ }
12965
+ function buildMasteryGates(units, sessions) {
12966
+ const gates = [];
12967
+ for (let i = 0; i < units.length - 1; i++) {
12968
+ const cur = units[i];
12969
+ const next = units[i + 1];
12970
+ const unitEvidence = sessions.filter((s) => s.unit_id === cur.id).flatMap((s) => s.exit_evidence || []).slice(0, 6);
12971
+ gates.push({
12972
+ phase_or_unit_id: cur.id,
12973
+ gate_name: `${cur.name} Mastery Gate`,
12974
+ exit_criteria: unitEvidence.length > 0 ? unitEvidence : [`Master all deliverables for ${cur.name}`],
12975
+ next_unit_id: next.id,
12976
+ remediation: {
12977
+ trigger: "FAIL_GATE_CRITERIA",
12978
+ focus_minutes: 15,
12979
+ action: `Review and complete failing practical criteria for ${cur.name} before starting ${next.name}`
12980
+ }
12981
+ });
12982
+ }
12983
+ return gates;
12984
+ }
12985
+ function dropCyclicConceptEdges(edges) {
12986
+ const pairSet = new Set(edges.map((e) => `${e.concept_code}|${e.requires}`));
12987
+ const nonSymmetric = edges.filter((e) => !pairSet.has(`${e.requires}|${e.concept_code}`));
12988
+ const deps = /* @__PURE__ */ new Map();
12989
+ const createsCycle = (a, b) => {
12990
+ const stack = [b];
12991
+ const seen = /* @__PURE__ */ new Set();
12992
+ while (stack.length > 0) {
12993
+ const n = stack.pop();
12994
+ if (n === a) return true;
12995
+ if (seen.has(n)) continue;
12996
+ seen.add(n);
12997
+ const targets = deps.get(n);
12998
+ if (targets) {
12999
+ for (const t of targets) stack.push(t);
13000
+ }
13001
+ }
13002
+ return false;
13003
+ };
13004
+ const out = [];
13005
+ for (const e of nonSymmetric) {
13006
+ if (createsCycle(e.concept_code, e.requires)) continue;
13007
+ if (!deps.has(e.concept_code)) deps.set(e.concept_code, /* @__PURE__ */ new Set());
13008
+ deps.get(e.concept_code).add(e.requires);
13009
+ out.push(e);
13010
+ }
13011
+ return out;
13012
+ }
13013
+ function buildConceptPrerequisites(sessions, nodeById, edges) {
13014
+ const firstSeen = /* @__PURE__ */ new Map();
13015
+ for (let i = 0; i < sessions.length; i++) {
13016
+ const s = sessions[i];
13017
+ for (const nid of s.node_ids) {
13018
+ const codes = nodeById.get(nid)?.concept_codes || [];
13019
+ for (const c of codes) {
13020
+ if (!firstSeen.has(c)) firstSeen.set(c, i);
13021
+ }
13022
+ }
13023
+ }
13024
+ const rawEdges = [];
13025
+ const seenPair = /* @__PURE__ */ new Set();
13026
+ for (const e of edges) {
13027
+ const fromNode = nodeById.get(e.from);
13028
+ const toNode = nodeById.get(e.to);
13029
+ if (!fromNode || !toNode) continue;
13030
+ const fromCodes = fromNode.concept_codes || [];
13031
+ const toCodes = toNode.concept_codes || [];
13032
+ for (const tc of toCodes) {
13033
+ for (const fc of fromCodes) {
13034
+ if (tc === fc) continue;
13035
+ const key = `${tc}|${fc}`;
13036
+ if (seenPair.has(key)) continue;
13037
+ seenPair.add(key);
13038
+ const firstSeenTc = firstSeen.get(tc) ?? 999;
13039
+ const firstSeenFc = firstSeen.get(fc) ?? 999;
13040
+ const supported = firstSeenFc <= firstSeenTc;
13041
+ rawEdges.push({
13042
+ concept_code: tc,
13043
+ requires: fc,
13044
+ source: "CONCEPT_LEVEL_PREREQ",
13045
+ confidence: supported ? 0.8 : 0.6,
13046
+ rationale: e.reason || `Derived from planning node dependency: ${fromNode.name} -> ${toNode.name}`,
13047
+ structure_supported: supported,
13048
+ needs_review: !supported,
13049
+ hub: false
13050
+ });
13051
+ }
13052
+ }
13053
+ }
13054
+ const fanOut = /* @__PURE__ */ new Map();
13055
+ for (const re of rawEdges) {
13056
+ fanOut.set(re.concept_code, (fanOut.get(re.concept_code) || 0) + 1);
13057
+ }
13058
+ for (const re of rawEdges) {
13059
+ if ((fanOut.get(re.concept_code) || 0) >= 6) {
13060
+ re.hub = true;
13061
+ re.confidence = Math.min(re.confidence, 0.5);
13062
+ re.needs_review = true;
13063
+ }
13064
+ }
13065
+ return dropCyclicConceptEdges(rawEdges);
13066
+ }
12784
13067
  async function buildCurriculumPlan(rawGraph, options) {
12785
13068
  const { constraints } = options;
12786
13069
  const warnings = [];
@@ -12876,6 +13159,9 @@ async function buildCurriculumPlan(rawGraph, options) {
12876
13159
  const seenNodes = /* @__PURE__ */ new Set();
12877
13160
  const multiPartNodes = new Set(packed.flatMap((s) => s.entries.filter((e) => e.totalParts > 1).map((e) => e.id)));
12878
13161
  const sessions = [];
13162
+ const allSeenConcepts = /* @__PURE__ */ new Set();
13163
+ const allSeenKeywords = /* @__PURE__ */ new Set();
13164
+ const conceptEncounterMap = /* @__PURE__ */ new Map();
12879
13165
  for (let i = 0; i < packed.length; i++) {
12880
13166
  const s = packed[i];
12881
13167
  for (const id of s.nodeIds) {
@@ -12920,6 +13206,16 @@ async function buildCurriculumPlan(rawGraph, options) {
12920
13206
  knowledge: s.knowledgeMinutes || 0,
12921
13207
  practice: s.practiceMinutes + (s.practiceMinutes === 0 && s.knowledgeMinutes > 0 ? Math.min(spareMinutes, 10) : 0)
12922
13208
  };
13209
+ const sessionConcepts = [...new Set(s.nodeIds.flatMap((id) => nodeById.get(id)?.concept_codes || []))];
13210
+ for (const cCode of sessionConcepts) {
13211
+ const curCount = (conceptEncounterMap.get(cCode) || 0) + 1;
13212
+ conceptEncounterMap.set(cCode, curCount);
13213
+ }
13214
+ const zpdResult = checkSessionZpd(i, s.nodeIds, nodeById, allSeenConcepts, allSeenKeywords, entryKw, warnings);
13215
+ const prereqDecisions = decidePrerequisites(ctx, nodeById, graph.edges, sessionIndexByNode, sessionOrderByIndex, constraints);
13216
+ if (zpdResult.bridgeRepair) {
13217
+ prereqDecisions.unshift(zpdResult.bridgeRepair);
13218
+ }
12923
13219
  sessions.push({
12924
13220
  id: lessonCode,
12925
13221
  unit_id: unit.id,
@@ -12940,8 +13236,8 @@ async function buildCurriculumPlan(rawGraph, options) {
12940
13236
  // Spiral pedagogy = apply at greater depth, not re-lecture.
12941
13237
  practice_minutes: sessionMinutes.practice,
12942
13238
  overhead_minutes: spec.overheadMinutes,
12943
- depth_assignments: assignDepths(s.nodeIds, nodeById),
12944
- prerequisite_decisions: decidePrerequisites(ctx, nodeById, graph.edges, sessionIndexByNode, sessionOrderByIndex, constraints),
13239
+ depth_assignments: assignDepths(s.nodeIds, nodeById, conceptEncounterMap),
13240
+ prerequisite_decisions: prereqDecisions,
12945
13241
  scaffold_decisions: decideScaffolds(ctx, nodeById, warnings),
12946
13242
  // Deliverable phrasing follows the node role: concept → evidence is the
12947
13243
  // explanation, product_step/skill → the artifact or activity itself.
@@ -12956,16 +13252,58 @@ async function buildCurriculumPlan(rawGraph, options) {
12956
13252
  bronze: "Complete the core deliverable for " + nodeNames[0] + " with provided scaffolding.",
12957
13253
  silver: "Complete all session deliverables independently.",
12958
13254
  gold: "Extend the deliverable: combine " + nodeNames.join(", ") + " in a self-chosen variant."
12959
- }
13255
+ },
13256
+ // P50: ZPD cognitive load status for this session
13257
+ zpd_status: zpdResult.status
12960
13258
  });
12961
13259
  }
12962
13260
  const unassigned = graph.nodes.map((n) => n.id).filter((id) => !seenNodes.has(id));
12963
13261
  if (unassigned.length > 0) throw new Error("Coverage violation: unassigned nodes " + unassigned.join(", "));
13262
+ if (options.llmFn && sessions.length > 0) {
13263
+ try {
13264
+ const sessionSummaries = sessions.map((s) => `${s.id}|${s.title}|objective: ${s.prose_objective.slice(0, 120)}|keywords: ${s.new_keywords.join("/")}`).join("\n");
13265
+ const dSys = 'You differentiate learning tasks. Output ONLY a JSON object mapping session-id to {"bronze":string,"silver":string,"gold":string}. Each tier ONE sentence: bronze = foundational task with provided scaffolding; silver = independent application; gold = creative extension combining session concepts. Same language as the objectives.';
13266
+ const dUsr = `Age band: ${constraints.age_band[0]}-${constraints.age_band[1]}. Entry level: ${constraints.entry_level}.
13267
+ Sessions:
13268
+ ${sessionSummaries}`;
13269
+ const raw = (await options.llmFn(dSys, dUsr)).trim();
13270
+ const match = raw.match(/\{[\s\S]*\}/);
13271
+ if (match) {
13272
+ const parsed = JSON.parse(match[0]);
13273
+ let upgraded = 0;
13274
+ for (const s of sessions) {
13275
+ const d = parsed[s.id];
13276
+ if (d && typeof d.bronze === "string" && d.bronze.length >= 10 && typeof d.silver === "string" && d.silver.length >= 10 && typeof d.gold === "string" && d.gold.length >= 10) {
13277
+ s.differentiation = { bronze: d.bronze, silver: d.silver, gold: d.gold };
13278
+ upgraded++;
13279
+ }
13280
+ }
13281
+ if (upgraded < sessions.length) warnings.push(`differentiation_llm_partial:${upgraded}/${sessions.length}`);
13282
+ } else {
13283
+ warnings.push("differentiation_llm_unparseable");
13284
+ }
13285
+ } catch (e) {
13286
+ warnings.push("differentiation_llm_failed:" + (e instanceof Error ? e.message.slice(0, 80) : String(e).slice(0, 80)));
13287
+ }
13288
+ }
12964
13289
  const glossaryScope = sessions.map((s) => ({
12965
13290
  session_id: s.id,
12966
13291
  terms: [...new Set(s.node_ids.flatMap((id) => nodeById.get(id).keywords))]
12967
13292
  }));
12968
- const planPayload = { units, sessions, course: { objectives: courseObjectives }, constraints };
13293
+ const conceptSpiralProgression = computeConceptSpiralProgression(sessions, nodeById);
13294
+ const walkingSkeleton = buildWalkingSkeleton(units, sessions);
13295
+ const masteryGates = buildMasteryGates(units, sessions);
13296
+ const conceptPrerequisites = buildConceptPrerequisites(sessions, nodeById, graph.edges);
13297
+ const planPayload = {
13298
+ units,
13299
+ sessions,
13300
+ course: { objectives: courseObjectives },
13301
+ constraints,
13302
+ walking_skeleton: walkingSkeleton,
13303
+ mastery_gates: masteryGates,
13304
+ concept_spiral_progression: conceptSpiralProgression,
13305
+ concept_prerequisites: conceptPrerequisites
13306
+ };
12969
13307
  const planHash = createHash("sha256").update(JSON.stringify(planPayload)).digest("hex").slice(0, 16);
12970
13308
  const plan = CurriculumPlanSchema.parse({
12971
13309
  schema_version: 1,
@@ -12977,6 +13315,10 @@ async function buildCurriculumPlan(rawGraph, options) {
12977
13315
  course: { objectives: courseObjectives, capstone_ref: constraints.capstone },
12978
13316
  units,
12979
13317
  sessions,
13318
+ walking_skeleton: walkingSkeleton,
13319
+ mastery_gates: masteryGates,
13320
+ concept_spiral_progression: conceptSpiralProgression,
13321
+ concept_prerequisites: conceptPrerequisites,
12980
13322
  glossary_scope: glossaryScope,
12981
13323
  translation: options.translation ?? { policy: "at_publish", target_language: null },
12982
13324
  coverage_report: { assigned_node_ids: [...seenNodes], unassigned_node_ids: [], warnings },
@@ -13008,6 +13350,13 @@ function buildSessionSliceContext(plan, lessonCode) {
13008
13350
  lines.push("- Prerequisite keywords: " + (s.prerequisite_keywords.join(", ") || "(none)"));
13009
13351
  lines.push("- Time split: knowledge " + s.knowledge_minutes + "m / practice " + s.practice_minutes + "m / overhead " + s.overhead_minutes + "m");
13010
13352
  lines.push("- Depth assignments: " + s.depth_assignments.map((d) => d.node_id + "=" + d.depth.toUpperCase() + "(" + d.source + ")").join("; "));
13353
+ if (s.zpd_status && s.zpd_status.verdict !== "OK") {
13354
+ lines.push("- ZPD alert: " + s.zpd_status.verdict + " (" + s.zpd_status.issues.join("; ") + ")");
13355
+ }
13356
+ const sessionSpirals = (plan.concept_spiral_progression || []).filter((e) => e.session_id === lessonCode);
13357
+ if (sessionSpirals.length > 0) {
13358
+ lines.push("- Spiral encounters: " + sessionSpirals.map((e) => `${e.concept_code}#${e.encounter_index}=${e.bloom_cap}(${e.depth.toUpperCase()})`).join("; "));
13359
+ }
13011
13360
  if (s.prerequisite_decisions.length > 0) {
13012
13361
  lines.push("- Prerequisite decisions [" + s.prerequisite_decisions.length + "]:");
13013
13362
  for (const d of s.prerequisite_decisions) lines.push(" * " + d.node_id + ": " + d.decision + " \u2014 " + d.reason);
@@ -13329,14 +13678,14 @@ function lintFrameworkPack(pack) {
13329
13678
  const primaryLang = pack.manifest.languages[0];
13330
13679
  const text = s.texts[primaryLang];
13331
13680
  if (!text) continue;
13332
- const norm = text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((w) => w.length > 2).sort().join(" ");
13333
- if (!norm) continue;
13334
- const prev = seen.get(norm);
13681
+ const norm2 = text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((w) => w.length > 2).sort().join(" ");
13682
+ if (!norm2) continue;
13683
+ const prev = seen.get(norm2);
13335
13684
  if (prev !== void 0) {
13336
13685
  issues.push({ severity: "WARNING", code: "DUP_TEXT_EXACT", message: `Text is token-identical to statement "${prev}"`, ref: s.id });
13337
13686
  } else {
13338
13687
  for (const [otherNorm, otherId] of seen.entries()) {
13339
- const a = new Set(norm.split(" "));
13688
+ const a = new Set(norm2.split(" "));
13340
13689
  const b = new Set(otherNorm.split(" "));
13341
13690
  let inter = 0;
13342
13691
  for (const w of a) if (b.has(w)) inter++;
@@ -13346,7 +13695,7 @@ function lintFrameworkPack(pack) {
13346
13695
  break;
13347
13696
  }
13348
13697
  }
13349
- seen.set(norm, s.id);
13698
+ seen.set(norm2, s.id);
13350
13699
  }
13351
13700
  }
13352
13701
  for (const m of pack.mappings ?? []) {
@@ -26087,6 +26436,229 @@ function extractStandardRefs(text) {
26087
26436
  return Array.from(new Set(matches));
26088
26437
  }
26089
26438
 
26439
+ // src/services/contextSlots.ts
26440
+ var LESSON_SLOT_BUDGETS = {
26441
+ ACT: { budget: 8e3 },
26442
+ GUIDE: { budget: 6e3 },
26443
+ QUIZ: { budget: 3500, priorities: ["A. Lesson Design Plan"] },
26444
+ SLIDE: { budget: 4500, priorities: ["B. Lesson Flow", "A. Lesson Design Plan"] },
26445
+ WKS: { budget: 4500, priorities: ["A. Lesson Design Plan", "B. Lesson Flow"] },
26446
+ EXIT_TICKET: { budget: 3e3, priorities: ["A. Lesson Design Plan", "B. Lesson Flow"] }
26447
+ };
26448
+ var KX_ONLY_TYPES = /* @__PURE__ */ new Set(["CODE", "HANDOUT", "EXT"]);
26449
+ var KX_SLOT_PRIORITIES = {
26450
+ QUIZ: ["Common Mistakes", "Self-Check Questions", "Key Terms", "Concept Narratives"],
26451
+ EXIT_TICKET: ["Self-Check Questions", "Key Terms"],
26452
+ WKS: ["Self-Check Questions", "Worked Micro-Examples", "Key Terms"],
26453
+ CODE: ["Worked Micro-Examples", "Key Terms", "Common Mistakes"],
26454
+ GUIDE: ["Common Mistakes", "Key Terms", "Concept Narratives"],
26455
+ HANDOUT: ["Key Terms", "Concept Narratives", "Common Mistakes"],
26456
+ SLIDE: ["Key Terms", "Worked Micro-Examples"],
26457
+ ACT: ["Worked Micro-Examples", "Common Mistakes"],
26458
+ EXT: ["Worked Micro-Examples", "Common Mistakes"]
26459
+ };
26460
+ var norm = (s) => s.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "");
26461
+ function extractActivityContractRows(lessonContent, artifactType, maxChars = 1500) {
26462
+ if (!lessonContent) return "";
26463
+ const wanted = norm(artifactType).replace(/_/g, "");
26464
+ const lines = lessonContent.split("\n");
26465
+ let inSeq = false;
26466
+ const headerRows = [];
26467
+ const matchedRows = [];
26468
+ const allRows = [];
26469
+ for (let i = 0; i < lines.length; i++) {
26470
+ const line = lines[i];
26471
+ const h = line.match(/^#{2,4}\s+(.*)$/);
26472
+ if (h) {
26473
+ const t2 = h[1];
26474
+ if (/activity\s*sequence/i.test(t2)) inSeq = true;
26475
+ else if (inSeq) break;
26476
+ continue;
26477
+ }
26478
+ if (!inSeq) continue;
26479
+ const t = line.trim();
26480
+ if (!t.startsWith("|")) continue;
26481
+ if (/^\|\s*[-: |]+\|\s*$/.test(t)) continue;
26482
+ const cells = t.split("|").slice(1, -1).map((c) => c.trim());
26483
+ if (cells.length >= 4) {
26484
+ if (headerRows.length === 0) {
26485
+ headerRows.push(t);
26486
+ continue;
26487
+ }
26488
+ allRows.push(t);
26489
+ const contract = cells[cells.length - 1] ?? "";
26490
+ const candidates = contract.split(/[,;/]/).map((c) => norm(c));
26491
+ if (candidates.some((c) => c === wanted || c.length > 3 && (c.includes(wanted) || wanted.includes(c)))) {
26492
+ matchedRows.push(t);
26493
+ }
26494
+ }
26495
+ }
26496
+ const rows = matchedRows.length > 0 ? matchedRows : allRows.slice(0, 3);
26497
+ if (rows.length === 0) return "";
26498
+ let out = headerRows[0] ?? "";
26499
+ for (const r of rows) {
26500
+ if (out.length + r.length + 1 > maxChars) break;
26501
+ out += "\n" + r;
26502
+ }
26503
+ return out;
26504
+ }
26505
+ function extractTieredScaffoldingBlock(lessonContent, maxChars = 900) {
26506
+ if (!lessonContent) return "";
26507
+ const lines = lessonContent.split("\n");
26508
+ let capture = null;
26509
+ for (const line of lines) {
26510
+ const h = line.match(/^#{2,4}\s+(.*)$/);
26511
+ if (h) {
26512
+ const isTierHeading = /elaborate|tiered|scaffold/i.test(h[1] ?? "");
26513
+ if (capture && !isTierHeading) break;
26514
+ if (isTierHeading) capture = [];
26515
+ continue;
26516
+ }
26517
+ if (capture) {
26518
+ capture.push(line);
26519
+ if (capture.join("").length >= maxChars) break;
26520
+ }
26521
+ }
26522
+ const body = (capture ?? []).join("\n").trim();
26523
+ return body ? body.slice(0, maxChars) : "";
26524
+ }
26525
+ function extractAssessmentMap(lessonContent, maxChars = 1200) {
26526
+ if (!lessonContent) return "";
26527
+ const lines = lessonContent.split("\n");
26528
+ let capture = null;
26529
+ for (const line of lines) {
26530
+ const h = line.match(/^#{2,4}\s+(.*)$/);
26531
+ if (h) {
26532
+ const isTarget = /assessment\s*map/i.test(h[1] ?? "");
26533
+ if (capture && !isTarget) break;
26534
+ if (isTarget) capture = [];
26535
+ continue;
26536
+ }
26537
+ if (capture) {
26538
+ capture.push(line);
26539
+ if (capture.join("").length >= maxChars) break;
26540
+ }
26541
+ }
26542
+ const body = (capture ?? []).join("\n").trim();
26543
+ return body ? body.slice(0, maxChars) : "";
26544
+ }
26545
+ function blockMeta(slot, source, text, verified, issues = []) {
26546
+ return { slot, source, chars: text.length, verified, issues };
26547
+ }
26548
+ function buildSatelliteContext(input) {
26549
+ const {
26550
+ artifactType,
26551
+ commonContext,
26552
+ lessonContent,
26553
+ lessonExcerpt,
26554
+ expositionContent,
26555
+ slcMarkdown,
26556
+ symbolLedgerBlock,
26557
+ pedagogyLabel,
26558
+ mode = "legacy"
26559
+ } = input;
26560
+ const type = (artifactType || "").toUpperCase().trim();
26561
+ if (mode === "legacy" || type === "LESSON") {
26562
+ const context2 = `${commonContext}
26563
+
26564
+ [CANONICAL LESSON PLAN (${pedagogyLabel ?? "LESSON"})]:
26565
+ ${lessonExcerpt.excerpt}${symbolLedgerBlock}`;
26566
+ return {
26567
+ context: context2,
26568
+ blocks: [
26569
+ blockMeta("commonContext", "COMPOSITE", commonContext, true),
26570
+ blockMeta("lessonExcerpt", "LESSON", lessonExcerpt.excerpt, lessonExcerpt.verified, lessonExcerpt.issues)
26571
+ ],
26572
+ verified: lessonExcerpt.verified,
26573
+ sectionAware: lessonExcerpt.sectionAware,
26574
+ issues: lessonExcerpt.issues,
26575
+ tokenEstimate: Math.round(context2.length / 4)
26576
+ };
26577
+ }
26578
+ const blocks = [];
26579
+ const issues = [];
26580
+ const parts = [commonContext];
26581
+ blocks.push(blockMeta("commonContext", "COMPOSITE", commonContext, true));
26582
+ const compositeHasKx = /###\s+KNOWLEDGE_EXPOSITION/.test(commonContext);
26583
+ if (expositionContent.trim() && !compositeHasKx) {
26584
+ const kxExcerpt = buildSectionAwareExcerpt(expositionContent, {
26585
+ priorities: KX_SLOT_PRIORITIES[type] ?? ["Key Terms", "Concept Narratives", "Worked Micro-Examples"],
26586
+ budget: 4500,
26587
+ sectionLanguageContract: slcMarkdown,
26588
+ artifactType: "KNOWLEDGE_EXPOSITION"
26589
+ });
26590
+ parts.push(`
26591
+
26592
+ [KNOWLEDGE_EXPOSITION (canonical knowledge \u2014 teach from this, do not contradict; scoped for ${type})]:
26593
+ ${kxExcerpt.excerpt}`);
26594
+ blocks.push(blockMeta("kxExcerpt:" + type, "KNOWLEDGE_EXPOSITION", kxExcerpt.excerpt, kxExcerpt.verified, kxExcerpt.issues));
26595
+ if (!kxExcerpt.verified) issues.push(...kxExcerpt.issues.map((i) => `kx:${i}`));
26596
+ }
26597
+ if (!KX_ONLY_TYPES.has(type)) {
26598
+ const spec = LESSON_SLOT_BUDGETS[type] ?? { budget: 12e3 };
26599
+ const excerpt = buildSectionAwareExcerpt(lessonContent, {
26600
+ priorities: spec.priorities ?? ["Artifact Contract", "A. Lesson Design Plan", "B. Lesson Flow", "Learning Objectives & Evidence", "Activity Sequence"],
26601
+ budget: spec.budget,
26602
+ sectionLanguageContract: slcMarkdown,
26603
+ artifactType: "LESSON"
26604
+ });
26605
+ parts.push(`
26606
+
26607
+ [CANONICAL LESSON PLAN (scoped for ${type})]:
26608
+ ${excerpt.excerpt}`);
26609
+ blocks.push(blockMeta("lessonExcerpt:" + type, "LESSON", excerpt.excerpt, excerpt.verified, excerpt.issues));
26610
+ if (!excerpt.verified) issues.push(...excerpt.issues.map((i) => `lesson:${i}`));
26611
+ if (type === "QUIZ" || type === "WKS") {
26612
+ const am = extractAssessmentMap(lessonContent, 1200);
26613
+ if (am) {
26614
+ parts.push(`
26615
+
26616
+ [ASSESSMENT MAP (criteria anchor \u2014 assess exactly these)]:
26617
+ ${am}`);
26618
+ blocks.push(blockMeta("assessmentMap:" + type, "LESSON", am, true));
26619
+ } else {
26620
+ issues.push(`assessment-map:unresolved:${type}`);
26621
+ }
26622
+ }
26623
+ if (symbolLedgerBlock) {
26624
+ parts.push(symbolLedgerBlock);
26625
+ blocks.push(blockMeta("symbolLedger", "LESSON", symbolLedgerBlock, true));
26626
+ }
26627
+ } else {
26628
+ const contractRows = extractActivityContractRows(lessonContent, type === "CODE" ? "CODE_LAB" : type, 1500);
26629
+ const tierBlock = type === "CODE" || type === "EXT" ? extractTieredScaffoldingBlock(lessonContent, 900) : "";
26630
+ const mini = [
26631
+ contractRows ? `### Activity Sequence rows assigned to ${type} (canonical \u2014 do not invent a different task):
26632
+ ${contractRows}` : "",
26633
+ tierBlock ? `### Tiered task ladder (from LESSON Elaborate phase):
26634
+ ${tierBlock}` : ""
26635
+ ].filter(Boolean).join("\n\n");
26636
+ if (mini) {
26637
+ parts.push(`
26638
+
26639
+ [LESSON ACTIVITY CONTRACT (mini-slot)]:
26640
+ ${mini}`);
26641
+ blocks.push(blockMeta("activityContract:" + type, "LESSON", mini, true));
26642
+ } else {
26643
+ issues.push(`activity-contract:unresolved:${type}`);
26644
+ blocks.push(blockMeta("activityContract:" + type, "LESSON", "", false, ["no-matching-rows"]));
26645
+ }
26646
+ if (type === "CODE" && symbolLedgerBlock) {
26647
+ parts.push(symbolLedgerBlock);
26648
+ blocks.push(blockMeta("symbolLedger", "LESSON", symbolLedgerBlock, true));
26649
+ }
26650
+ }
26651
+ const context = parts.join("");
26652
+ return {
26653
+ context,
26654
+ blocks,
26655
+ verified: blocks.filter((b) => b.slot !== "commonContext").every((b) => b.verified),
26656
+ sectionAware: blocks.some((b) => b.slot.startsWith("lessonExcerpt") || b.slot.startsWith("kxExcerpt")),
26657
+ issues,
26658
+ tokenEstimate: Math.round(context.length / 4)
26659
+ };
26660
+ }
26661
+
26090
26662
  // src/services/lessonProductionService.ts
26091
26663
  var __filename2 = typeof import.meta?.url === "string" && typeof fileURLToPath === "function" ? fileURLToPath(import.meta.url) : "";
26092
26664
  var _resolvedDir = __filename2 ? path3.dirname(__filename2) : typeof __dirname !== "undefined" ? __dirname : process.cwd();
@@ -26659,9 +27231,9 @@ ${renderHorizonPromptBlock(horizon)}`;
26659
27231
  console.warn(`[produceSingleLesson] Notice: Curriculum Horizon extraction:`, hErr?.message || hErr);
26660
27232
  }
26661
27233
  let productSpecBlock = "";
26662
- const buildGroundTruthBlock = () => {
27234
+ const buildGroundTruthBlock = (includeKx = true) => {
26663
27235
  const parts = [];
26664
- if (expositionContext) {
27236
+ if (includeKx && expositionContext) {
26665
27237
  parts.push(`### KNOWLEDGE_EXPOSITION (CANONICAL KNOWLEDGE \u2014 teach from this, do not contradict)
26666
27238
  ${expositionContext}`);
26667
27239
  }
@@ -26695,10 +27267,10 @@ ${sessionSliceContext}` : "";
26695
27267
  const guardrailBlock = `
26696
27268
 
26697
27269
  ${platformGuardrail}`;
26698
- const assembleCommonContext = (sg) => `${baseContextPrefix}
27270
+ const assembleCommonContext = (sg, includeKx = true) => `${baseContextPrefix}
26699
27271
 
26700
27272
  [CONTENT STYLE GUIDE EXCERPT]:
26701
- ${sg}${standardsBlock}${glossaryBlock}${buildGroundTruthBlock()}${sessionSliceBlock}${horizonBlock}${guardrailBlock}`;
27273
+ ${sg}${standardsBlock}${glossaryBlock}${buildGroundTruthBlock(includeKx)}${sessionSliceBlock}${horizonBlock}${guardrailBlock}`;
26702
27274
  let commonContext = assembleCommonContext(effectiveStyleGuide);
26703
27275
  const MAX_COMPOSITE_PROMPT_CHARS = 3e4;
26704
27276
  const runnerOptions = options.customInference ? { customInference: options.customInference } : {};
@@ -27107,10 +27679,32 @@ ${currentContent}` }],
27107
27679
  - Entry Source File: \`${symbolLedger.entryFileName || symbolLedger.primarySymbol}\`
27108
27680
  - Key Identifiers to inherit verbatim: ${symbolLedger.keySymbols.map((s) => `\`${s}\``).join(", ")}
27109
27681
  - INVARIANT: You MUST use these exact identifier names in all code examples, exercises, and test assertions. Do NOT invent new struct/class names!` : "";
27110
- const satelliteContext = `${commonContext}
27111
-
27112
- [CANONICAL LESSON PLAN (${pedagogyLabel})]:
27113
- ${lessonExcerpt}${symbolLedgerBlock}`;
27682
+ const routingMode = options.contextRoutingMode ?? "legacy";
27683
+ const kxFreeCommonContext = routingMode === "hybrid" ? assembleCommonContext(effectiveStyleGuide, false) : "";
27684
+ const satelliteContexts = {};
27685
+ const satelliteContextFor = (artifactType) => {
27686
+ const key = artifactType.toUpperCase();
27687
+ if (!satelliteContexts[key]) {
27688
+ const built = buildSatelliteContext({
27689
+ artifactType: key,
27690
+ commonContext: routingMode === "hybrid" ? kxFreeCommonContext : commonContext,
27691
+ lessonContent,
27692
+ lessonExcerpt: lessonExcerptResult,
27693
+ expositionContent: expositionContext,
27694
+ slcMarkdown,
27695
+ symbolLedgerBlock,
27696
+ pedagogyLabel,
27697
+ mode: routingMode
27698
+ });
27699
+ satelliteContexts[key] = built.context;
27700
+ onProgress?.(
27701
+ "@content",
27702
+ `[CONTEXT] ${key} satellite context: ${built.context.length} chars (${built.blocks.map((b) => `${b.slot}:${b.chars}`).join(", ")})`,
27703
+ { type: "progress", promptChars: built.context.length, artifactType: key }
27704
+ );
27705
+ }
27706
+ return satelliteContexts[key];
27707
+ };
27114
27708
  const judgeSat = (sat, content) => {
27115
27709
  if (gateModeFor(gates, sat) !== "LLM_JUDGE") return Promise.resolve();
27116
27710
  const det = validateArtifactDeterministic({ content, refPack });
@@ -27191,7 +27785,7 @@ ${languageDirective}
27191
27785
  ${buildHeadingDirective("ACT", slcMarkdown, targetLang)}`;
27192
27786
  const rawAct = await runCurriculumAIInference(
27193
27787
  [{ role: "user", content: actPrompt }],
27194
- satelliteContext,
27788
+ satelliteContextFor("ACT"),
27195
27789
  runnerOptions,
27196
27790
  (chunk, type) => {
27197
27791
  options.onProgress?.("@activity", chunk, { type: type || "content", artifactType: "ACT" });
@@ -27261,7 +27855,7 @@ ${languageDirective}
27261
27855
  ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
27262
27856
  const rawQuiz = await runCurriculumAIInference(
27263
27857
  [{ role: "user", content: quizPrompt }],
27264
- satelliteContext,
27858
+ satelliteContextFor("QUIZ"),
27265
27859
  runnerOptions,
27266
27860
  (chunk, type) => {
27267
27861
  options.onProgress?.("@assessor", chunk, { type: type || "content", artifactType: "QUIZ" });
@@ -27314,7 +27908,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
27314
27908
  headingDirective: buildHeadingDirective("SLIDE", slcMarkdown, targetLang),
27315
27909
  groundContext: slideGroundContext,
27316
27910
  productSpecBlock: productSpecBlock || void 0,
27317
- satelliteContext,
27911
+ satelliteContext: satelliteContextFor("SLIDE"),
27318
27912
  runnerOptions,
27319
27913
  onProgress: (agent, msg, meta) => {
27320
27914
  options.onProgress?.(agent, msg, meta || { type: "content", artifactType: "SLIDE" });
@@ -27398,7 +27992,7 @@ footer: "Curriculum OS \u2022 ${lessonCode} (${pedagogyLabel})"
27398
27992
  });
27399
27993
  const rawSlide = await runCurriculumAIInference(
27400
27994
  [{ role: "user", content: slidePrompt }],
27401
- satelliteContext,
27995
+ satelliteContextFor("SLIDE"),
27402
27996
  runnerOptions,
27403
27997
  (chunk, type) => {
27404
27998
  options.onProgress?.("@illustrator", chunk, { type: type || "content", artifactType: "SLIDE" });
@@ -27459,7 +28053,7 @@ ${languageDirective}
27459
28053
  ${buildHeadingDirective("GUIDE", slcMarkdown, targetLang)}`;
27460
28054
  const rawGuide = await runCurriculumAIInference(
27461
28055
  [{ role: "user", content: guidePrompt }],
27462
- satelliteContext,
28056
+ satelliteContextFor("GUIDE"),
27463
28057
  runnerOptions,
27464
28058
  (chunk, type) => {
27465
28059
  options.onProgress?.("@content", chunk, { type: type || "chunk", artifactType: "GUIDE" });
@@ -27511,7 +28105,7 @@ ${languageDirective}
27511
28105
  ${buildHeadingDirective("HANDOUT", slcMarkdown, targetLang)}`;
27512
28106
  const rawHandout = await runCurriculumAIInference(
27513
28107
  [{ role: "user", content: handoutPrompt }],
27514
- satelliteContext,
28108
+ satelliteContextFor("HANDOUT"),
27515
28109
  runnerOptions,
27516
28110
  (chunk, type) => {
27517
28111
  options.onProgress?.("@content", chunk, { type: type || "chunk", artifactType: "HANDOUT" });
@@ -27567,7 +28161,7 @@ ${languageDirective}
27567
28161
  ${buildHeadingDirective("WKS", slcMarkdown, targetLang)}`;
27568
28162
  const rawWks = await runCurriculumAIInference(
27569
28163
  [{ role: "user", content: wksPrompt }],
27570
- satelliteContext,
28164
+ satelliteContextFor("WKS"),
27571
28165
  runnerOptions,
27572
28166
  (chunk, type) => {
27573
28167
  options.onProgress?.("@content", chunk, { type: type || "chunk", artifactType: "WKS" });
@@ -27627,7 +28221,7 @@ ${languageDirective}
27627
28221
  ${buildHeadingDirective("CODE", slcMarkdown, targetLang)}`;
27628
28222
  const rawCode = await runCurriculumAIInference(
27629
28223
  [{ role: "user", content: codePrompt }],
27630
- satelliteContext,
28224
+ satelliteContextFor("CODE"),
27631
28225
  runnerOptions,
27632
28226
  (chunk, type) => {
27633
28227
  options.onProgress?.("@activity", chunk, { type: type || "chunk", artifactType: "CODE" });
@@ -27714,7 +28308,7 @@ ${languageDirective}
27714
28308
  ${buildHeadingDirective("EXT", slcMarkdown, targetLang)}`;
27715
28309
  const rawExt = await runCurriculumAIInference(
27716
28310
  [{ role: "user", content: extPrompt }],
27717
- satelliteContext,
28311
+ satelliteContextFor("EXT"),
27718
28312
  runnerOptions,
27719
28313
  (chunk, type) => {
27720
28314
  options.onProgress?.("@activity", chunk, { type: type || "chunk", artifactType: "EXT" });
@@ -29691,26 +30285,40 @@ Return concise JSON matching:
29691
30285
  "technicalGotchas": ["Important safety or compatibility note 1", "Note 2"]
29692
30286
  }`;
29693
30287
  let rawContent = "";
29694
- await streamLLMWithFallback(
29695
- "You are an authoritative STEM & CS curriculum researcher. Output valid JSON only.",
29696
- researchPrompt,
29697
- apiKeys,
29698
- (chunk, type) => {
29699
- if (type === "content") rawContent += chunk;
29700
- onChunk?.(chunk, type);
29701
- },
29702
- options.model,
29703
- options.provider,
29704
- // Research may run live web grounding — generous budget, still idle-guarded.
29705
- resolveStreamBudget(void 0, {
29706
- idleMs: options.idleTimeoutMs,
29707
- totalMs: options.timeoutMs,
29708
- model: options.model,
29709
- provider: options.provider
29710
- }),
29711
- options.signal,
29712
- options.onProviderEvent
29713
- );
30288
+ if (options.customInference) {
30289
+ rawContent = await options.customInference({
30290
+ systemInstruction: "You are an authoritative STEM & CS curriculum researcher. Output valid JSON only.",
30291
+ userPrompt: researchPrompt,
30292
+ messages: [{ role: "user", content: researchPrompt }],
30293
+ temperature: 0.2,
30294
+ maxTokens: 32768,
30295
+ onChunk: (token, type) => {
30296
+ if (type === "content") rawContent += token;
30297
+ if (type === "content" || type === "thought") onChunk?.(token, type);
30298
+ }
30299
+ }) || "";
30300
+ } else {
30301
+ await streamLLMWithFallback(
30302
+ "You are an authoritative STEM & CS curriculum researcher. Output valid JSON only.",
30303
+ researchPrompt,
30304
+ apiKeys,
30305
+ (chunk, type) => {
30306
+ if (type === "content") rawContent += chunk;
30307
+ onChunk?.(chunk, type);
30308
+ },
30309
+ options.model,
30310
+ options.provider,
30311
+ // Research may run live web grounding — generous budget, still idle-guarded.
30312
+ resolveStreamBudget(void 0, {
30313
+ idleMs: options.idleTimeoutMs,
30314
+ totalMs: options.timeoutMs,
30315
+ model: options.model,
30316
+ provider: options.provider
30317
+ }),
30318
+ options.signal,
30319
+ options.onProviderEvent
30320
+ );
30321
+ }
29714
30322
  let parsedResearch = {
29715
30323
  groundTruthSummary: `Verified ecosystem standards for ${projectName}`,
29716
30324
  hardwareVersion: "Standard Environment",
@@ -30800,6 +31408,75 @@ var DeterministicStructuralLinter = class {
30800
31408
  strengths
30801
31409
  };
30802
31410
  }
31411
+ /**
31412
+ * P50: Validates macro-pedagogical invariants across a CurriculumPlan.
31413
+ * Checks:
31414
+ * 1. ZPD violations without self-healing recap (NO_ZPD_BRIDGE)
31415
+ * 2. Walking Skeleton existence (Unit 1 delivers working software)
31416
+ * 3. Inter-unit Mastery Gate presence
31417
+ */
31418
+ static lintPlan(plan) {
31419
+ const findings = [];
31420
+ const strengths = [];
31421
+ let score = 100;
31422
+ for (const s of plan.sessions) {
31423
+ if (s.zpd_status?.verdict === "TOO_MANY_NEW") {
31424
+ score -= 10;
31425
+ findings.push({
31426
+ id: `PLAN_TOO_MANY_NEW_${s.id}`,
31427
+ dimension: "CONSTRUCTIVE_ALIGNMENT",
31428
+ severity: "MINOR",
31429
+ title: `Cognitive Overload in Session ${s.id}`,
31430
+ description: s.zpd_status.issues.join("; ") || `Session introduces too many new concepts/keywords, exceeding ZPD capacity.`,
31431
+ remediationAdvice: `Distribute new concepts across multiple sessions or introduce via scaffolding.`,
31432
+ affectedElement: s.id
31433
+ });
31434
+ } else if (s.zpd_status?.verdict === "NO_ZPD_BRIDGE") {
31435
+ const hasRecap = s.prerequisite_decisions.some((d) => d.decision === "recap_in_lesson");
31436
+ if (!hasRecap) {
31437
+ score -= 15;
31438
+ findings.push({
31439
+ id: `PLAN_NO_ZPD_BRIDGE_${s.id}`,
31440
+ dimension: "CONSTRUCTIVE_ALIGNMENT",
31441
+ severity: "MAJOR",
31442
+ title: `Unhealed ZPD Bridge in Session ${s.id}`,
31443
+ description: `Session introduces new concepts with 0 known concept bridges, and lacks recap scaffolding.`,
31444
+ remediationAdvice: `Add a recap_in_lesson prerequisite decision to anchor new learning in prior concepts.`,
31445
+ affectedElement: s.id
31446
+ });
31447
+ }
31448
+ }
31449
+ }
31450
+ if (!plan.walking_skeleton || plan.walking_skeleton.epitome_deliverables.length === 0) {
31451
+ score -= 10;
31452
+ findings.push({
31453
+ id: "PLAN_MISSING_WALKING_SKELETON",
31454
+ dimension: "CONSTRUCTIVE_ALIGNMENT",
31455
+ severity: "MINOR",
31456
+ title: "Missing Walking Skeleton Definition",
31457
+ description: "Plan does not declare an Epitome (walking skeleton) in Unit 1.",
31458
+ remediationAdvice: "Ensure Unit 1 defines minimal end-to-end deliverables."
31459
+ });
31460
+ } else {
31461
+ strengths.push(`Unit ${plan.walking_skeleton.epitome_unit_id} establishes an end-to-end Walking Skeleton (Epitome).`);
31462
+ }
31463
+ if (plan.units.length > 1 && (!plan.mastery_gates || plan.mastery_gates.length === 0)) {
31464
+ score -= 10;
31465
+ findings.push({
31466
+ id: "PLAN_MISSING_MASTERY_GATES",
31467
+ dimension: "5E_INSTRUCTIONAL_FIDELITY",
31468
+ severity: "MINOR",
31469
+ title: "Missing Inter-Unit Mastery Gates",
31470
+ description: "Multi-unit course lacks formal transition gates between units.",
31471
+ remediationAdvice: "Define exit criteria and remediation sprints for each inter-unit boundary."
31472
+ });
31473
+ } else if (plan.mastery_gates && plan.mastery_gates.length > 0) {
31474
+ strengths.push(`${plan.mastery_gates.length} inter-unit Mastery Gates defined with remediation protocols.`);
31475
+ }
31476
+ score = Math.max(0, Math.min(100, score));
31477
+ const passed = score >= 80 && !findings.some((f) => f.severity === "CRITICAL");
31478
+ return { passed, score, findings, strengths };
31479
+ }
30803
31480
  };
30804
31481
 
30805
31482
  // src/evaluators/academicAuditor.ts
@@ -32434,6 +33111,6 @@ function renderMediaPlaceholder(entry) {
32434
33111
  return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
32435
33112
  }
32436
33113
 
32437
- export { ACT_TEMPLATE, ARTIFACT_DEPENDENCY_ROUTING, 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_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_KX_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DEFAULT_VIETNAMESE_SECTION_HEADINGS, 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, GeneratedSlideArraySchema, GeneratedSlideSchema, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HANDOUT_TEMPLATE, HandoutSchema, HandoutSectionSchema, HybridBlueprintArraySchema, HybridBlueprintItemSchema, HybridDeckSlideArraySchema, HybridDeckSlideSchema, HybridPipelineError, InstructionSectionSchema, InstructionStepSchema, JudgeCriterionSchema, LAYER_IDLE_BUDGET_MS, 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, SATELLITE_LESSON_PRIORITIES, SCIENCE_LAB_TEMPLATE, SELF_LAB_TEMPLATE, SLIDE_CANONICAL_METHODOLOGY, SLIDE_LAYOUT_PRESETS, SLIDE_TEMPLATE, STANDARD_REF_REGEX, STANDARD_SOT_FILES, STATION_ROTATION_TEMPLATE, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SilverTierSchema, SlideBlueprintArraySchema, SlideBlueprintItemSchema, 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, atomicWriteFileSync, auditCurriculumQualityFlow, auditQualityReport, buildActivityPrompt, buildCodeLabPrompt, buildCurriculumContext, buildCurriculumPlan, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildExtensionPrompt, buildHandoutPrompt, buildHeadingDirective, buildHtmlDeckSlidePrompt, buildImagePrompt, buildJudgePrompt, buildLanguageDirective, buildLessonExcerpt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildProjectInstructionPrompt, buildSectionAwareExcerpt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWorksheetPrompt, closeTruncatedJson, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createContextMissingError, createCurriculumStorage, createIdleAbortController, createStreamAbortController, createStreamAbortSignal, createStreamChunkExtractor, curateMediaLedger, designerTools, detectProjectPedagogy, emitUsage, ensureExpositionForLesson, ensureKnowledgeExposition, evaluateStandardsCoverage, executeCurriculumCommand, executeSlideProductionWorkflow, exportAllProjectQuizzes, expositionCacheKey, extractCurriculumHorizon, extractJsonArray, extractScopeSequenceRows, extractSectionHeadingsFromSLC, extractSessionSlice, extractStandardRefs, extractStreamChunk, extractSymbolLedger, extractThoughtAndContent, findStandardStatement, 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, normalizeSlcContract, packagerTools, parseAllSessions, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderFrameworkFromPlan, renderHorizonPromptBlock, renderMediaPlaceholder, researcherTools, resolveApiKey, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTargetLanguageCode, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, stripLlmJsonWrappers, targetLanguageDisplayName, techSmeTools, topoSort, uploadAssetToBucket, validateArtifactDependencies, validateCurriculumPlan, validateFrameworkPack, validateHorizonCompliance, validateHybridDeckSlides, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
33114
+ export { ACT_TEMPLATE, ARTIFACT_DEPENDENCY_ROUTING, 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, ConceptPrerequisiteEdgeSchema, ConceptSpiralEncounterSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_KX_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DEFAULT_VIETNAMESE_SECTION_HEADINGS, 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, GeneratedSlideArraySchema, GeneratedSlideSchema, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HANDOUT_TEMPLATE, HandoutSchema, HandoutSectionSchema, HybridBlueprintArraySchema, HybridBlueprintItemSchema, HybridDeckSlideArraySchema, HybridDeckSlideSchema, HybridPipelineError, InstructionSectionSchema, InstructionStepSchema, JudgeCriterionSchema, LAYER_IDLE_BUDGET_MS, LAYER_TOTAL_BUDGET_MS, LESSON_PLAN_TEMPLATE, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MappingKindSchema, MarpSlideSchema, MasteryGateSchema, 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, SATELLITE_LESSON_PRIORITIES, SCIENCE_LAB_TEMPLATE, SELF_LAB_TEMPLATE, SLIDE_CANONICAL_METHODOLOGY, SLIDE_LAYOUT_PRESETS, SLIDE_TEMPLATE, STANDARD_REF_REGEX, STANDARD_SOT_FILES, STATION_ROTATION_TEMPLATE, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SessionZpdStatusSchema, SilverTierSchema, SlideBlueprintArraySchema, SlideBlueprintItemSchema, 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, WalkingSkeletonSchema, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, ZpdVerdictSchema, activityTools, analystTools, analyzeProjectCreationIntent, assertAcyclic, assessorTools, assignDepths, atomicWriteFileSync, auditCurriculumQualityFlow, auditQualityReport, buildActivityPrompt, buildCodeLabPrompt, buildConceptPrerequisites, buildCurriculumContext, buildCurriculumPlan, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildExtensionPrompt, buildHandoutPrompt, buildHeadingDirective, buildHtmlDeckSlidePrompt, buildImagePrompt, buildJudgePrompt, buildLanguageDirective, buildLessonExcerpt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildMasteryGates, buildProjectInstructionPrompt, buildSatelliteContext, buildSectionAwareExcerpt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWalkingSkeleton, buildWorksheetPrompt, checkSessionZpd, closeTruncatedJson, computeConceptSpiralProgression, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createContextMissingError, createCurriculumStorage, createIdleAbortController, createStreamAbortController, createStreamAbortSignal, createStreamChunkExtractor, curateMediaLedger, designerTools, detectProjectPedagogy, dropCyclicConceptEdges, emitUsage, ensureExpositionForLesson, ensureKnowledgeExposition, evaluateStandardsCoverage, executeCurriculumCommand, executeSlideProductionWorkflow, exportAllProjectQuizzes, expositionCacheKey, extractActivityContractRows, extractAssessmentMap, extractCurriculumHorizon, extractJsonArray, extractScopeSequenceRows, extractSectionHeadingsFromSLC, extractSessionSlice, extractStandardRefs, extractStreamChunk, extractSymbolLedger, extractThoughtAndContent, extractTieredScaffoldingBlock, findStandardStatement, 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, normalizeSlcContract, packagerTools, parseAllSessions, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderFrameworkFromPlan, renderHorizonPromptBlock, renderMediaPlaceholder, researcherTools, resolveApiKey, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTargetLanguageCode, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, stripLlmJsonWrappers, targetLanguageDisplayName, techSmeTools, topoSort, uploadAssetToBucket, validateArtifactDependencies, validateCurriculumPlan, validateFrameworkPack, validateHorizonCompliance, validateHybridDeckSlides, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
32438
33115
  //# sourceMappingURL=index.mjs.map
32439
33116
  //# sourceMappingURL=index.mjs.map