@thanh01.pmt/curriculum-kit 1.4.49 → 1.4.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -11030,10 +11030,13 @@ function buildUnitGroupings(graph, orderedIds) {
11030
11030
  }
11031
11031
  function computePackingSpec(constraints) {
11032
11032
  const overheadMinutes = Math.round(constraints.session_duration_minutes * constraints.overhead_ratio);
11033
+ const upperAge = constraints.age_band?.[1];
11034
+ const maxNew = upperAge !== void 0 && upperAge > 15 ? MAX_NEW_CONCEPTS_PER_SESSION_ADULT : MAX_NEW_CONCEPTS_PER_SESSION_K12;
11033
11035
  return {
11034
11036
  contentBudget: constraints.session_duration_minutes - overheadMinutes,
11035
11037
  overheadMinutes,
11036
- sessionDurationMinutes: constraints.session_duration_minutes
11038
+ sessionDurationMinutes: constraints.session_duration_minutes,
11039
+ maxNewConceptsPerSession: maxNew
11037
11040
  };
11038
11041
  }
11039
11042
  var filledOf = (s) => s.knowledgeMinutes + s.practiceMinutes;
@@ -11116,6 +11119,15 @@ function packUnitSessions(group, nodeById, spec, warnings) {
11116
11119
  continue;
11117
11120
  }
11118
11121
  const minutes = node.estimated_minutes;
11122
+ if (spec.maxNewConceptsPerSession && spec.maxNewConceptsPerSession > 0 && current.entries.length > 0) {
11123
+ const currentConcepts = new Set(current.nodeIds.flatMap((nid) => nodeById.get(nid)?.concept_codes || []));
11124
+ const incoming = nodeById.get(id)?.concept_codes || [];
11125
+ const wouldAdd = incoming.filter((c) => !currentConcepts.has(c)).length;
11126
+ if (currentConcepts.size + wouldAdd > spec.maxNewConceptsPerSession) {
11127
+ warnings.push(`ZPD pack flush: session ${group.key}#${sessions.length + 1} cut at ${currentConcepts.size} new concepts (budget ${spec.maxNewConceptsPerSession})`);
11128
+ flush();
11129
+ }
11130
+ }
11119
11131
  if (current.entries.length > 0 && filled() + minutes > spec.contentBudget) {
11120
11132
  const displaced = cutBackToCheckpoint(current, nodeById, spec, warnings);
11121
11133
  if (displaced.length > 0) {
@@ -11274,12 +11286,12 @@ function checkSessionZpd(sessionIndex, nodeIds, nodeById, allSeenConcepts, allSe
11274
11286
  const knownKeywords = allKeywords.filter((k) => allSeenKeywords.has(k.toLowerCase()) || entryKw.has(k.toLowerCase()));
11275
11287
  const issues = [];
11276
11288
  let verdict = "OK";
11277
- if (concepts.length > 0 && newConcepts.length > 2) {
11289
+ if (newConcepts.length > MAX_NEW_CONCEPTS_PER_SESSION_K12) {
11278
11290
  verdict = "TOO_MANY_NEW";
11279
- issues.push(`${newConcepts.length} new concepts exceed ZPD limit (max 2)`);
11280
- } else if (concepts.length === 0 && newKeywords.length > 4) {
11281
- verdict = "TOO_MANY_NEW";
11282
- issues.push(`${newKeywords.length} new keywords exceed ZPD limit (max 4)`);
11291
+ issues.push(`${newConcepts.length} new concepts exceed ZPD limit (max ${MAX_NEW_CONCEPTS_PER_SESSION_K12})`);
11292
+ }
11293
+ if (newKeywords.length > 4) {
11294
+ issues.push(`Evidence for judge: ${newKeywords.length} new keywords in session (noisy proxy, not a gate)`);
11283
11295
  }
11284
11296
  if (sessionIndex > 0) {
11285
11297
  if (concepts.length > 1 && knownConcepts.length === 0) {
@@ -29951,14 +29963,14 @@ var DeterministicStructuralLinter = class {
29951
29963
  let score = 100;
29952
29964
  for (const s of plan.sessions) {
29953
29965
  if (s.zpd_status?.verdict === "TOO_MANY_NEW") {
29954
- score -= 10;
29966
+ score -= 25;
29955
29967
  findings.push({
29956
29968
  id: `PLAN_TOO_MANY_NEW_${s.id}`,
29957
29969
  dimension: "CONSTRUCTIVE_ALIGNMENT",
29958
- severity: "MINOR",
29970
+ severity: "CRITICAL",
29959
29971
  title: `Cognitive Overload in Session ${s.id}`,
29960
- description: s.zpd_status.issues.join("; ") || `Session introduces too many new concepts/keywords, exceeding ZPD capacity.`,
29961
- remediationAdvice: `Distribute new concepts across multiple sessions or introduce via scaffolding.`,
29972
+ description: s.zpd_status.issues.join("; ") || `Session introduces more new concepts than the ZPD limit allows.`,
29973
+ remediationAdvice: `Split the session: move overflow concepts to a later session (the packer flushes on concept budget automatically).`,
29962
29974
  affectedElement: s.id
29963
29975
  });
29964
29976
  } else if (s.zpd_status?.verdict === "NO_ZPD_BRIDGE") {