@thanh01.pmt/curriculum-kit 1.4.35 → 1.4.37

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 (35) hide show
  1. package/dist/ai/index.cjs +57 -1
  2. package/dist/ai/index.cjs.map +1 -1
  3. package/dist/ai/index.d.cts +2 -2
  4. package/dist/ai/index.d.ts +2 -2
  5. package/dist/ai/index.mjs +57 -1
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/{gateSettings-DabOqP6_.d.cts → gateSettings-oo5tCUS_.d.cts} +18 -0
  8. package/dist/{gateSettings-DabOqP6_.d.ts → gateSettings-oo5tCUS_.d.ts} +18 -0
  9. package/dist/index.cjs +793 -51
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +251 -74
  12. package/dist/index.d.ts +251 -74
  13. package/dist/index.mjs +775 -52
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/pipeline/index.cjs +57 -1
  16. package/dist/pipeline/index.cjs.map +1 -1
  17. package/dist/pipeline/index.mjs +57 -1
  18. package/dist/pipeline/index.mjs.map +1 -1
  19. package/dist/schemas/index.cjs +63 -1
  20. package/dist/schemas/index.cjs.map +1 -1
  21. package/dist/schemas/index.d.cts +436 -33
  22. package/dist/schemas/index.d.ts +436 -33
  23. package/dist/schemas/index.mjs +58 -2
  24. package/dist/schemas/index.mjs.map +1 -1
  25. package/dist/standards/index.d.cts +2 -2
  26. package/dist/standards/index.d.ts +2 -2
  27. package/dist/workflow/index.cjs +84 -2
  28. package/dist/workflow/index.cjs.map +1 -1
  29. package/dist/workflow/index.d.cts +3 -3
  30. package/dist/workflow/index.d.ts +3 -3
  31. package/dist/workflow/index.mjs +84 -2
  32. package/dist/workflow/index.mjs.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/{standardsCoverageGate-DR5YTtlt.d.cts → standardsCoverageGate-49pJq5t8.d.cts} +6 -6
  35. 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,263 @@ 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
+ canonicalExcerpt: lessonExcerpt.excerpt
26577
+ };
26578
+ }
26579
+ const blocks = [];
26580
+ const issues = [];
26581
+ const parts = [commonContext];
26582
+ blocks.push(blockMeta("commonContext", "COMPOSITE", commonContext, true));
26583
+ let excerptSlot;
26584
+ let miniSlot;
26585
+ const compositeHasKx = /###\s+KNOWLEDGE_EXPOSITION/.test(commonContext);
26586
+ if (expositionContent.trim() && !compositeHasKx) {
26587
+ const kxExcerpt = buildSectionAwareExcerpt(expositionContent, {
26588
+ priorities: KX_SLOT_PRIORITIES[type] ?? ["Key Terms", "Concept Narratives", "Worked Micro-Examples"],
26589
+ budget: 4500,
26590
+ sectionLanguageContract: slcMarkdown,
26591
+ artifactType: "KNOWLEDGE_EXPOSITION"
26592
+ });
26593
+ parts.push(`
26594
+
26595
+ [KNOWLEDGE_EXPOSITION (canonical knowledge \u2014 teach from this, do not contradict; scoped for ${type})]:
26596
+ ${kxExcerpt.excerpt}`);
26597
+ blocks.push(blockMeta("kxExcerpt:" + type, "KNOWLEDGE_EXPOSITION", kxExcerpt.excerpt, kxExcerpt.verified, kxExcerpt.issues));
26598
+ if (!kxExcerpt.verified) issues.push(...kxExcerpt.issues.map((i) => `kx:${i}`));
26599
+ }
26600
+ if (!KX_ONLY_TYPES.has(type)) {
26601
+ const spec = LESSON_SLOT_BUDGETS[type] ?? { budget: 12e3 };
26602
+ const excerpt = buildSectionAwareExcerpt(lessonContent, {
26603
+ priorities: spec.priorities ?? ["Artifact Contract", "A. Lesson Design Plan", "B. Lesson Flow", "Learning Objectives & Evidence", "Activity Sequence"],
26604
+ budget: spec.budget,
26605
+ sectionLanguageContract: slcMarkdown,
26606
+ artifactType: "LESSON"
26607
+ });
26608
+ const excerptBlock = `
26609
+
26610
+ [CANONICAL LESSON PLAN (scoped for ${type})]:
26611
+ ${excerpt.excerpt}`;
26612
+ parts.push(excerptBlock);
26613
+ excerptSlot = excerptBlock;
26614
+ blocks.push(blockMeta("lessonExcerpt:" + type, "LESSON", excerpt.excerpt, excerpt.verified, excerpt.issues));
26615
+ if (!excerpt.verified) issues.push(...excerpt.issues.map((i) => `lesson:${i}`));
26616
+ if (type === "QUIZ" || type === "WKS") {
26617
+ const am = extractAssessmentMap(lessonContent, 1200);
26618
+ if (am) {
26619
+ parts.push(`
26620
+
26621
+ [ASSESSMENT MAP (criteria anchor \u2014 assess exactly these)]:
26622
+ ${am}`);
26623
+ blocks.push(blockMeta("assessmentMap:" + type, "LESSON", am, true));
26624
+ } else {
26625
+ issues.push(`assessment-map:unresolved:${type}`);
26626
+ }
26627
+ }
26628
+ if (symbolLedgerBlock) {
26629
+ parts.push(symbolLedgerBlock);
26630
+ blocks.push(blockMeta("symbolLedger", "LESSON", symbolLedgerBlock, true));
26631
+ }
26632
+ } else {
26633
+ const contractRows = extractActivityContractRows(lessonContent, type === "CODE" ? "CODE_LAB" : type, 1500);
26634
+ const tierBlock = type === "CODE" || type === "EXT" ? extractTieredScaffoldingBlock(lessonContent, 900) : "";
26635
+ const mini = [
26636
+ contractRows ? `### Activity Sequence rows assigned to ${type} (canonical \u2014 do not invent a different task):
26637
+ ${contractRows}` : "",
26638
+ tierBlock ? `### Tiered task ladder (from LESSON Elaborate phase):
26639
+ ${tierBlock}` : ""
26640
+ ].filter(Boolean).join("\n\n");
26641
+ if (mini) {
26642
+ const miniBlock = `
26643
+
26644
+ [LESSON ACTIVITY CONTRACT (mini-slot)]:
26645
+ ${mini}`;
26646
+ parts.push(miniBlock);
26647
+ miniSlot = miniBlock;
26648
+ blocks.push(blockMeta("activityContract:" + type, "LESSON", mini, true));
26649
+ } else {
26650
+ issues.push(`activity-contract:unresolved:${type}`);
26651
+ blocks.push(blockMeta("activityContract:" + type, "LESSON", "", false, ["no-matching-rows"]));
26652
+ }
26653
+ if (type === "CODE" && symbolLedgerBlock) {
26654
+ parts.push(symbolLedgerBlock);
26655
+ blocks.push(blockMeta("symbolLedger", "LESSON", symbolLedgerBlock, true));
26656
+ }
26657
+ }
26658
+ const context = parts.join("");
26659
+ return {
26660
+ context,
26661
+ blocks,
26662
+ verified: blocks.filter((b) => b.slot !== "commonContext").every((b) => b.verified),
26663
+ sectionAware: blocks.some((b) => b.slot.startsWith("lessonExcerpt") || b.slot.startsWith("kxExcerpt")),
26664
+ issues,
26665
+ tokenEstimate: Math.round(context.length / 4),
26666
+ // Judge ground truth = exactly what THIS type consumed (scoped or mini slot).
26667
+ canonicalExcerpt: (miniSlot ?? excerptSlot ?? lessonExcerpt.excerpt).trim()
26668
+ };
26669
+ }
26670
+ var ACTIVITY_ALIGNMENT_LOG_ONLY_UNTIL = /* @__PURE__ */ new Date("2026-09-23T00:00:00Z");
26671
+ function isActivityAlignmentLogOnly(now = /* @__PURE__ */ new Date()) {
26672
+ const env = (process.env.DRIFT_ALIGNMENT_LOG_ONLY ?? "").toLowerCase().trim();
26673
+ if (env === "false" || env === "0") return false;
26674
+ if (env === "true" || env === "1") return true;
26675
+ return now < ACTIVITY_ALIGNMENT_LOG_ONLY_UNTIL;
26676
+ }
26677
+ function evaluateActivityAlignment(canonicalExcerpt, generatedContent, now = /* @__PURE__ */ new Date()) {
26678
+ const mode = isActivityAlignmentLogOnly(now) ? "log_only" : "enforcing";
26679
+ if (!canonicalExcerpt || !canonicalExcerpt.trim()) {
26680
+ return { checked: false, passed: null, matchedTokens: [], missingTokens: [], mode };
26681
+ }
26682
+ const content = (generatedContent || "").toLowerCase();
26683
+ const stripped = canonicalExcerpt.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
26684
+ const latin = Array.from(new Set(stripped.match(/[a-z][a-z0-9_]{3,}/g) ?? []));
26685
+ const cjk = Array.from(new Set(canonicalExcerpt.match(/[\u4e00-\u9fff]{2,}/g) ?? []));
26686
+ const tokens = [...latin, ...cjk];
26687
+ if (tokens.length === 0) {
26688
+ return { checked: false, passed: null, matchedTokens: [], missingTokens: [], mode };
26689
+ }
26690
+ const matchedTokens = tokens.filter((t) => content.includes(t));
26691
+ const missingTokens = tokens.filter((t) => !content.includes(t));
26692
+ const passed = matchedTokens.length > 0;
26693
+ return { checked: true, passed, matchedTokens: matchedTokens.slice(0, 10), missingTokens: missingTokens.slice(0, 10), mode };
26694
+ }
26695
+
26090
26696
  // src/services/lessonProductionService.ts
26091
26697
  var __filename2 = typeof import.meta?.url === "string" && typeof fileURLToPath === "function" ? fileURLToPath(import.meta.url) : "";
26092
26698
  var _resolvedDir = __filename2 ? path3.dirname(__filename2) : typeof __dirname !== "undefined" ? __dirname : process.cwd();
@@ -26659,9 +27265,9 @@ ${renderHorizonPromptBlock(horizon)}`;
26659
27265
  console.warn(`[produceSingleLesson] Notice: Curriculum Horizon extraction:`, hErr?.message || hErr);
26660
27266
  }
26661
27267
  let productSpecBlock = "";
26662
- const buildGroundTruthBlock = () => {
27268
+ const buildGroundTruthBlock = (includeKx = true) => {
26663
27269
  const parts = [];
26664
- if (expositionContext) {
27270
+ if (includeKx && expositionContext) {
26665
27271
  parts.push(`### KNOWLEDGE_EXPOSITION (CANONICAL KNOWLEDGE \u2014 teach from this, do not contradict)
26666
27272
  ${expositionContext}`);
26667
27273
  }
@@ -26695,10 +27301,10 @@ ${sessionSliceContext}` : "";
26695
27301
  const guardrailBlock = `
26696
27302
 
26697
27303
  ${platformGuardrail}`;
26698
- const assembleCommonContext = (sg) => `${baseContextPrefix}
27304
+ const assembleCommonContext = (sg, includeKx = true) => `${baseContextPrefix}
26699
27305
 
26700
27306
  [CONTENT STYLE GUIDE EXCERPT]:
26701
- ${sg}${standardsBlock}${glossaryBlock}${buildGroundTruthBlock()}${sessionSliceBlock}${horizonBlock}${guardrailBlock}`;
27307
+ ${sg}${standardsBlock}${glossaryBlock}${buildGroundTruthBlock(includeKx)}${sessionSliceBlock}${horizonBlock}${guardrailBlock}`;
26702
27308
  let commonContext = assembleCommonContext(effectiveStyleGuide);
26703
27309
  const MAX_COMPOSITE_PROMPT_CHARS = 3e4;
26704
27310
  const runnerOptions = options.customInference ? { customInference: options.customInference } : {};
@@ -27107,10 +27713,34 @@ ${currentContent}` }],
27107
27713
  - Entry Source File: \`${symbolLedger.entryFileName || symbolLedger.primarySymbol}\`
27108
27714
  - Key Identifiers to inherit verbatim: ${symbolLedger.keySymbols.map((s) => `\`${s}\``).join(", ")}
27109
27715
  - 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}`;
27716
+ const routingMode = options.contextRoutingMode ?? "legacy";
27717
+ const kxFreeCommonContext = routingMode === "hybrid" ? assembleCommonContext(effectiveStyleGuide, false) : "";
27718
+ const satelliteContexts = {};
27719
+ const satelliteContextMeta = {};
27720
+ const satelliteContextFor = (artifactType) => {
27721
+ const key = artifactType.toUpperCase();
27722
+ if (!satelliteContexts[key]) {
27723
+ const built = buildSatelliteContext({
27724
+ artifactType: key,
27725
+ commonContext: routingMode === "hybrid" ? kxFreeCommonContext : commonContext,
27726
+ lessonContent,
27727
+ lessonExcerpt: lessonExcerptResult,
27728
+ expositionContent: expositionContext,
27729
+ slcMarkdown,
27730
+ symbolLedgerBlock,
27731
+ pedagogyLabel,
27732
+ mode: routingMode
27733
+ });
27734
+ satelliteContexts[key] = built.context;
27735
+ satelliteContextMeta[key] = built;
27736
+ onProgress?.(
27737
+ "@content",
27738
+ `[CONTEXT] ${key} satellite context: ${built.context.length} chars (${built.blocks.map((b) => `${b.slot}:${b.chars}`).join(", ")})`,
27739
+ { type: "progress", promptChars: built.context.length, artifactType: key }
27740
+ );
27741
+ }
27742
+ return satelliteContexts[key];
27743
+ };
27114
27744
  const judgeSat = (sat, content) => {
27115
27745
  if (gateModeFor(gates, sat) !== "LLM_JUDGE") return Promise.resolve();
27116
27746
  const det = validateArtifactDeterministic({ content, refPack });
@@ -27130,6 +27760,30 @@ ${lessonExcerpt}${symbolLedgerBlock}`;
27130
27760
  }
27131
27761
  });
27132
27762
  }
27763
+ const slotMeta = satelliteContextMeta[sat.toUpperCase()];
27764
+ if (slotMeta) {
27765
+ const alignment = evaluateActivityAlignment(slotMeta.canonicalExcerpt, content);
27766
+ if (alignment.checked && alignment.passed === false) {
27767
+ const note = `activity-alignment drift vs ${sat} contract slot (matched: ${alignment.matchedTokens.join(", ") || "none"}); canonical tokens absent from output`;
27768
+ if (alignment.mode === "enforcing") {
27769
+ const critique = validatorRepairPrompt([{ code: "scope-drift", detail: note, evidence: alignment.missingTokens }]);
27770
+ onProgress?.("@reviewer", `\u26D4 ${sat} activity-alignment drift FAIL: ${note}`);
27771
+ return storage.updateArtifactState(projectId, lessonCode, sat, {
27772
+ state: "rejected",
27773
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
27774
+ contentHash: computeContentHash(content),
27775
+ review: {
27776
+ decision: "NEEDS_REVISION",
27777
+ reviewedBy: "@heuristic-linter",
27778
+ reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
27779
+ score: 0,
27780
+ critique
27781
+ }
27782
+ });
27783
+ }
27784
+ onProgress?.("@reviewer", `\u{1F9ED} [log-only] ${sat} activity-alignment drift: ${note}`);
27785
+ }
27786
+ }
27133
27787
  return judgeSatelliteArtifact({
27134
27788
  storage,
27135
27789
  projectId,
@@ -27142,7 +27796,7 @@ ${lessonExcerpt}${symbolLedgerBlock}`;
27142
27796
  onProgress,
27143
27797
  targetLang,
27144
27798
  canonicalLessonContent: lessonContent,
27145
- canonicalLessonExcerpt: lessonExcerpt
27799
+ canonicalLessonExcerpt: slotMeta?.canonicalExcerpt ?? lessonExcerpt
27146
27800
  });
27147
27801
  };
27148
27802
  const actRelPath = `_content/${unitCode}/ACT_${lessonCode}.md`;
@@ -27191,7 +27845,7 @@ ${languageDirective}
27191
27845
  ${buildHeadingDirective("ACT", slcMarkdown, targetLang)}`;
27192
27846
  const rawAct = await runCurriculumAIInference(
27193
27847
  [{ role: "user", content: actPrompt }],
27194
- satelliteContext,
27848
+ satelliteContextFor("ACT"),
27195
27849
  runnerOptions,
27196
27850
  (chunk, type) => {
27197
27851
  options.onProgress?.("@activity", chunk, { type: type || "content", artifactType: "ACT" });
@@ -27261,7 +27915,7 @@ ${languageDirective}
27261
27915
  ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
27262
27916
  const rawQuiz = await runCurriculumAIInference(
27263
27917
  [{ role: "user", content: quizPrompt }],
27264
- satelliteContext,
27918
+ satelliteContextFor("QUIZ"),
27265
27919
  runnerOptions,
27266
27920
  (chunk, type) => {
27267
27921
  options.onProgress?.("@assessor", chunk, { type: type || "content", artifactType: "QUIZ" });
@@ -27314,7 +27968,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
27314
27968
  headingDirective: buildHeadingDirective("SLIDE", slcMarkdown, targetLang),
27315
27969
  groundContext: slideGroundContext,
27316
27970
  productSpecBlock: productSpecBlock || void 0,
27317
- satelliteContext,
27971
+ satelliteContext: satelliteContextFor("SLIDE"),
27318
27972
  runnerOptions,
27319
27973
  onProgress: (agent, msg, meta) => {
27320
27974
  options.onProgress?.(agent, msg, meta || { type: "content", artifactType: "SLIDE" });
@@ -27398,7 +28052,7 @@ footer: "Curriculum OS \u2022 ${lessonCode} (${pedagogyLabel})"
27398
28052
  });
27399
28053
  const rawSlide = await runCurriculumAIInference(
27400
28054
  [{ role: "user", content: slidePrompt }],
27401
- satelliteContext,
28055
+ satelliteContextFor("SLIDE"),
27402
28056
  runnerOptions,
27403
28057
  (chunk, type) => {
27404
28058
  options.onProgress?.("@illustrator", chunk, { type: type || "content", artifactType: "SLIDE" });
@@ -27459,7 +28113,7 @@ ${languageDirective}
27459
28113
  ${buildHeadingDirective("GUIDE", slcMarkdown, targetLang)}`;
27460
28114
  const rawGuide = await runCurriculumAIInference(
27461
28115
  [{ role: "user", content: guidePrompt }],
27462
- satelliteContext,
28116
+ satelliteContextFor("GUIDE"),
27463
28117
  runnerOptions,
27464
28118
  (chunk, type) => {
27465
28119
  options.onProgress?.("@content", chunk, { type: type || "chunk", artifactType: "GUIDE" });
@@ -27511,7 +28165,7 @@ ${languageDirective}
27511
28165
  ${buildHeadingDirective("HANDOUT", slcMarkdown, targetLang)}`;
27512
28166
  const rawHandout = await runCurriculumAIInference(
27513
28167
  [{ role: "user", content: handoutPrompt }],
27514
- satelliteContext,
28168
+ satelliteContextFor("HANDOUT"),
27515
28169
  runnerOptions,
27516
28170
  (chunk, type) => {
27517
28171
  options.onProgress?.("@content", chunk, { type: type || "chunk", artifactType: "HANDOUT" });
@@ -27567,7 +28221,7 @@ ${languageDirective}
27567
28221
  ${buildHeadingDirective("WKS", slcMarkdown, targetLang)}`;
27568
28222
  const rawWks = await runCurriculumAIInference(
27569
28223
  [{ role: "user", content: wksPrompt }],
27570
- satelliteContext,
28224
+ satelliteContextFor("WKS"),
27571
28225
  runnerOptions,
27572
28226
  (chunk, type) => {
27573
28227
  options.onProgress?.("@content", chunk, { type: type || "chunk", artifactType: "WKS" });
@@ -27627,7 +28281,7 @@ ${languageDirective}
27627
28281
  ${buildHeadingDirective("CODE", slcMarkdown, targetLang)}`;
27628
28282
  const rawCode = await runCurriculumAIInference(
27629
28283
  [{ role: "user", content: codePrompt }],
27630
- satelliteContext,
28284
+ satelliteContextFor("CODE"),
27631
28285
  runnerOptions,
27632
28286
  (chunk, type) => {
27633
28287
  options.onProgress?.("@activity", chunk, { type: type || "chunk", artifactType: "CODE" });
@@ -27714,7 +28368,7 @@ ${languageDirective}
27714
28368
  ${buildHeadingDirective("EXT", slcMarkdown, targetLang)}`;
27715
28369
  const rawExt = await runCurriculumAIInference(
27716
28370
  [{ role: "user", content: extPrompt }],
27717
- satelliteContext,
28371
+ satelliteContextFor("EXT"),
27718
28372
  runnerOptions,
27719
28373
  (chunk, type) => {
27720
28374
  options.onProgress?.("@activity", chunk, { type: type || "chunk", artifactType: "EXT" });
@@ -30814,6 +31468,75 @@ var DeterministicStructuralLinter = class {
30814
31468
  strengths
30815
31469
  };
30816
31470
  }
31471
+ /**
31472
+ * P50: Validates macro-pedagogical invariants across a CurriculumPlan.
31473
+ * Checks:
31474
+ * 1. ZPD violations without self-healing recap (NO_ZPD_BRIDGE)
31475
+ * 2. Walking Skeleton existence (Unit 1 delivers working software)
31476
+ * 3. Inter-unit Mastery Gate presence
31477
+ */
31478
+ static lintPlan(plan) {
31479
+ const findings = [];
31480
+ const strengths = [];
31481
+ let score = 100;
31482
+ for (const s of plan.sessions) {
31483
+ if (s.zpd_status?.verdict === "TOO_MANY_NEW") {
31484
+ score -= 10;
31485
+ findings.push({
31486
+ id: `PLAN_TOO_MANY_NEW_${s.id}`,
31487
+ dimension: "CONSTRUCTIVE_ALIGNMENT",
31488
+ severity: "MINOR",
31489
+ title: `Cognitive Overload in Session ${s.id}`,
31490
+ description: s.zpd_status.issues.join("; ") || `Session introduces too many new concepts/keywords, exceeding ZPD capacity.`,
31491
+ remediationAdvice: `Distribute new concepts across multiple sessions or introduce via scaffolding.`,
31492
+ affectedElement: s.id
31493
+ });
31494
+ } else if (s.zpd_status?.verdict === "NO_ZPD_BRIDGE") {
31495
+ const hasRecap = s.prerequisite_decisions.some((d) => d.decision === "recap_in_lesson");
31496
+ if (!hasRecap) {
31497
+ score -= 15;
31498
+ findings.push({
31499
+ id: `PLAN_NO_ZPD_BRIDGE_${s.id}`,
31500
+ dimension: "CONSTRUCTIVE_ALIGNMENT",
31501
+ severity: "MAJOR",
31502
+ title: `Unhealed ZPD Bridge in Session ${s.id}`,
31503
+ description: `Session introduces new concepts with 0 known concept bridges, and lacks recap scaffolding.`,
31504
+ remediationAdvice: `Add a recap_in_lesson prerequisite decision to anchor new learning in prior concepts.`,
31505
+ affectedElement: s.id
31506
+ });
31507
+ }
31508
+ }
31509
+ }
31510
+ if (!plan.walking_skeleton || plan.walking_skeleton.epitome_deliverables.length === 0) {
31511
+ score -= 10;
31512
+ findings.push({
31513
+ id: "PLAN_MISSING_WALKING_SKELETON",
31514
+ dimension: "CONSTRUCTIVE_ALIGNMENT",
31515
+ severity: "MINOR",
31516
+ title: "Missing Walking Skeleton Definition",
31517
+ description: "Plan does not declare an Epitome (walking skeleton) in Unit 1.",
31518
+ remediationAdvice: "Ensure Unit 1 defines minimal end-to-end deliverables."
31519
+ });
31520
+ } else {
31521
+ strengths.push(`Unit ${plan.walking_skeleton.epitome_unit_id} establishes an end-to-end Walking Skeleton (Epitome).`);
31522
+ }
31523
+ if (plan.units.length > 1 && (!plan.mastery_gates || plan.mastery_gates.length === 0)) {
31524
+ score -= 10;
31525
+ findings.push({
31526
+ id: "PLAN_MISSING_MASTERY_GATES",
31527
+ dimension: "5E_INSTRUCTIONAL_FIDELITY",
31528
+ severity: "MINOR",
31529
+ title: "Missing Inter-Unit Mastery Gates",
31530
+ description: "Multi-unit course lacks formal transition gates between units.",
31531
+ remediationAdvice: "Define exit criteria and remediation sprints for each inter-unit boundary."
31532
+ });
31533
+ } else if (plan.mastery_gates && plan.mastery_gates.length > 0) {
31534
+ strengths.push(`${plan.mastery_gates.length} inter-unit Mastery Gates defined with remediation protocols.`);
31535
+ }
31536
+ score = Math.max(0, Math.min(100, score));
31537
+ const passed = score >= 80 && !findings.some((f) => f.severity === "CRITICAL");
31538
+ return { passed, score, findings, strengths };
31539
+ }
30817
31540
  };
30818
31541
 
30819
31542
  // src/evaluators/academicAuditor.ts
@@ -32448,6 +33171,6 @@ function renderMediaPlaceholder(entry) {
32448
33171
  return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
32449
33172
  }
32450
33173
 
32451
- 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 };
33174
+ 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, evaluateActivityAlignment, 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, isActivityAlignmentLogOnly, 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 };
32452
33175
  //# sourceMappingURL=index.mjs.map
32453
33176
  //# sourceMappingURL=index.mjs.map