@thanh01.pmt/curriculum-kit 1.4.48 → 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.d.cts CHANGED
@@ -10,8 +10,8 @@ export { A as AutoRepairOptions, a as AutoRepairResult, B as BundleTier, G as Ge
10
10
  import { I as ICurriculumStorage, P as ProjectStatusReport, S as SmartResumeContext, Q as QualityAuditReport } from './types-Bgk-C4K2.cjs';
11
11
  export { b as ArtifactLifecycleInfo, A as ArtifactLifecycleState, L as LessonArtifactSummary, c as PipelineState, R as ReviewRecord, a as SotDocument, T as TaskLifecycleState } from './types-Bgk-C4K2.cjs';
12
12
  export { FileSystemCurriculumAdapter, FileSystemStorageOptions, STANDARD_SOT_FILES, StorageFactoryOptions, SupabaseCurriculumAdapter, SupabaseStorageConfig, atomicWriteFileSync, computeContentHash, createCurriculumStorage } from './storage/index.cjs';
13
- import { F as FrameworkPack, C as CoverageGateReport } from './standardsCoverageGate-CLnq0d0s.cjs';
14
- export { B as BloomHintSchema, a as ClassificationSchema, m as CoverageGateInput, h as FrameworkMapping, d as FrameworkMappingSchema, f as FrameworkPackManifest, b as FrameworkPackManifestSchema, e as FrameworkPackSchema, g as FrameworkStatement, c as FrameworkStatementSchema, G as GradeBandSchema, i as MappingKind, M as MappingKindSchema, P as PackLintIssue, k as PackValidationResult, j as RecordProvenance, R as RecordProvenanceSchema, S as StatementCoverageRow, n as evaluateStandardsCoverage, l as lintFrameworkPack, v as validateFrameworkPack } from './standardsCoverageGate-CLnq0d0s.cjs';
13
+ import { F as FrameworkPack, C as CoverageGateReport } from './standardsCoverageGate-49pJq5t8.cjs';
14
+ export { B as BloomHintSchema, a as ClassificationSchema, m as CoverageGateInput, h as FrameworkMapping, d as FrameworkMappingSchema, f as FrameworkPackManifest, b as FrameworkPackManifestSchema, e as FrameworkPackSchema, g as FrameworkStatement, c as FrameworkStatementSchema, G as GradeBandSchema, i as MappingKind, M as MappingKindSchema, P as PackLintIssue, k as PackValidationResult, j as RecordProvenance, R as RecordProvenanceSchema, S as StatementCoverageRow, n as evaluateStandardsCoverage, l as lintFrameworkPack, v as validateFrameworkPack } from './standardsCoverageGate-49pJq5t8.cjs';
15
15
  import { z } from 'zod';
16
16
  import { R as ResolvedGateSettings } from './gateSettings-JoqERuS1.cjs';
17
17
  export { A as ArtifactType, B as BoundaryPeek, b as CurriculumArtifactType, C as CurriculumGateMode, h as CurriculumHorizon, D as DEFAULT_GATE_SETTINGS, f as DetailedLessonBridge, E as ExtractCurriculumHorizonOptions, G as GateSettings, H as HorizonSessionSnapshot, i as HorizonValidationResult, c as ScaffoldingLevel, S as SingleArtifactRequest, a as SingleArtifactResult, k as extractCurriculumHorizon, g as gateModeFor, e as generateSingleArtifact, d as getArtifactMetadata, j as parseAllSessions, p as parseGateSettings, l as renderHorizonPromptBlock, r as resolveGateSettings, v as validateHorizonCompliance } from './gateSettings-JoqERuS1.cjs';
@@ -249,16 +249,16 @@ declare const LessonEntitySchema: z.ZodObject<{
249
249
  conceptRefs: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
250
250
  }, "strip", z.ZodTypeAny, {
251
251
  code: string;
252
+ objective: string;
253
+ evidence: string;
252
254
  successCriteria: string;
253
255
  standardRefs: string[];
254
256
  conceptRefs: string[];
255
- objective: string;
256
- evidence: string;
257
257
  }, {
258
258
  code: string;
259
- successCriteria: string;
260
259
  objective: string;
261
260
  evidence: string;
261
+ successCriteria: string;
262
262
  standardRefs?: string[] | undefined;
263
263
  conceptRefs?: string[] | undefined;
264
264
  }>, "many">>;
@@ -275,7 +275,6 @@ declare const LessonEntitySchema: z.ZodObject<{
275
275
  durationMinutes: z.ZodDefault<z.ZodNumber>;
276
276
  artifactContract: z.ZodString;
277
277
  }, "strip", z.ZodTypeAny, {
278
- durationMinutes: number;
279
278
  seq: number;
280
279
  phase: string;
281
280
  activityType: string;
@@ -285,6 +284,7 @@ declare const LessonEntitySchema: z.ZodObject<{
285
284
  teacherMove: string;
286
285
  outputEvidence: string;
287
286
  lo: string[];
287
+ durationMinutes: number;
288
288
  artifactContract: string;
289
289
  }, {
290
290
  seq: number;
@@ -317,17 +317,16 @@ declare const LessonEntitySchema: z.ZodObject<{
317
317
  }, "strip", z.ZodTypeAny, {
318
318
  lessonId: string;
319
319
  title: string;
320
+ estimatedDuration: string;
320
321
  learningObjectives: {
321
322
  code: string;
323
+ objective: string;
324
+ evidence: string;
322
325
  successCriteria: string;
323
326
  standardRefs: string[];
324
327
  conceptRefs: string[];
325
- objective: string;
326
- evidence: string;
327
328
  }[];
328
- estimatedDuration: string;
329
329
  activitySequence: {
330
- durationMinutes: number;
331
330
  seq: number;
332
331
  phase: string;
333
332
  activityType: string;
@@ -337,6 +336,7 @@ declare const LessonEntitySchema: z.ZodObject<{
337
336
  teacherMove: string;
338
337
  outputEvidence: string;
339
338
  lo: string[];
339
+ durationMinutes: number;
340
340
  artifactContract: string;
341
341
  }[];
342
342
  assessmentMap: Record<string, string>[];
@@ -349,15 +349,15 @@ declare const LessonEntitySchema: z.ZodObject<{
349
349
  }, {
350
350
  lessonId: string;
351
351
  title: string;
352
+ estimatedDuration?: string | undefined;
352
353
  learningObjectives?: {
353
354
  code: string;
354
- successCriteria: string;
355
355
  objective: string;
356
356
  evidence: string;
357
+ successCriteria: string;
357
358
  standardRefs?: string[] | undefined;
358
359
  conceptRefs?: string[] | undefined;
359
360
  }[] | undefined;
360
- estimatedDuration?: string | undefined;
361
361
  activitySequence?: {
362
362
  seq: number;
363
363
  phase: string;
@@ -1123,6 +1123,13 @@ interface PackingSpec {
1123
1123
  contentBudget: number;
1124
1124
  overheadMinutes: number;
1125
1125
  sessionDurationMinutes: number;
1126
+ /** 2026-09-18 RC-2: cognitive budget — max DISTINCT new concepts per
1127
+ * session (Vygotsky ZPD constant). 0 disables the check. The minute
1128
+ * budget alone packs knowledge-dense sessions (observed: 4 concepts in
1129
+ * one 90m K-12 session); flushing early on this budget is a STRUCTURAL
1130
+ * rule — it counts and cuts, it never reorders across prerequisite
1131
+ * edges (teaching order preserved by construction). */
1132
+ maxNewConceptsPerSession?: number;
1126
1133
  }
1127
1134
  declare function computePackingSpec(constraints: PlanConstraints): PackingSpec;
1128
1135
  interface PackedEntry {
package/dist/index.d.ts CHANGED
@@ -10,8 +10,8 @@ export { A as AutoRepairOptions, a as AutoRepairResult, B as BundleTier, G as Ge
10
10
  import { I as ICurriculumStorage, P as ProjectStatusReport, S as SmartResumeContext, Q as QualityAuditReport } from './types-Bgk-C4K2.js';
11
11
  export { b as ArtifactLifecycleInfo, A as ArtifactLifecycleState, L as LessonArtifactSummary, c as PipelineState, R as ReviewRecord, a as SotDocument, T as TaskLifecycleState } from './types-Bgk-C4K2.js';
12
12
  export { FileSystemCurriculumAdapter, FileSystemStorageOptions, STANDARD_SOT_FILES, StorageFactoryOptions, SupabaseCurriculumAdapter, SupabaseStorageConfig, atomicWriteFileSync, computeContentHash, createCurriculumStorage } from './storage/index.js';
13
- import { F as FrameworkPack, C as CoverageGateReport } from './standardsCoverageGate-CLnq0d0s.js';
14
- export { B as BloomHintSchema, a as ClassificationSchema, m as CoverageGateInput, h as FrameworkMapping, d as FrameworkMappingSchema, f as FrameworkPackManifest, b as FrameworkPackManifestSchema, e as FrameworkPackSchema, g as FrameworkStatement, c as FrameworkStatementSchema, G as GradeBandSchema, i as MappingKind, M as MappingKindSchema, P as PackLintIssue, k as PackValidationResult, j as RecordProvenance, R as RecordProvenanceSchema, S as StatementCoverageRow, n as evaluateStandardsCoverage, l as lintFrameworkPack, v as validateFrameworkPack } from './standardsCoverageGate-CLnq0d0s.js';
13
+ import { F as FrameworkPack, C as CoverageGateReport } from './standardsCoverageGate-49pJq5t8.js';
14
+ export { B as BloomHintSchema, a as ClassificationSchema, m as CoverageGateInput, h as FrameworkMapping, d as FrameworkMappingSchema, f as FrameworkPackManifest, b as FrameworkPackManifestSchema, e as FrameworkPackSchema, g as FrameworkStatement, c as FrameworkStatementSchema, G as GradeBandSchema, i as MappingKind, M as MappingKindSchema, P as PackLintIssue, k as PackValidationResult, j as RecordProvenance, R as RecordProvenanceSchema, S as StatementCoverageRow, n as evaluateStandardsCoverage, l as lintFrameworkPack, v as validateFrameworkPack } from './standardsCoverageGate-49pJq5t8.js';
15
15
  import { z } from 'zod';
16
16
  import { R as ResolvedGateSettings } from './gateSettings-JoqERuS1.js';
17
17
  export { A as ArtifactType, B as BoundaryPeek, b as CurriculumArtifactType, C as CurriculumGateMode, h as CurriculumHorizon, D as DEFAULT_GATE_SETTINGS, f as DetailedLessonBridge, E as ExtractCurriculumHorizonOptions, G as GateSettings, H as HorizonSessionSnapshot, i as HorizonValidationResult, c as ScaffoldingLevel, S as SingleArtifactRequest, a as SingleArtifactResult, k as extractCurriculumHorizon, g as gateModeFor, e as generateSingleArtifact, d as getArtifactMetadata, j as parseAllSessions, p as parseGateSettings, l as renderHorizonPromptBlock, r as resolveGateSettings, v as validateHorizonCompliance } from './gateSettings-JoqERuS1.js';
@@ -249,16 +249,16 @@ declare const LessonEntitySchema: z.ZodObject<{
249
249
  conceptRefs: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
250
250
  }, "strip", z.ZodTypeAny, {
251
251
  code: string;
252
+ objective: string;
253
+ evidence: string;
252
254
  successCriteria: string;
253
255
  standardRefs: string[];
254
256
  conceptRefs: string[];
255
- objective: string;
256
- evidence: string;
257
257
  }, {
258
258
  code: string;
259
- successCriteria: string;
260
259
  objective: string;
261
260
  evidence: string;
261
+ successCriteria: string;
262
262
  standardRefs?: string[] | undefined;
263
263
  conceptRefs?: string[] | undefined;
264
264
  }>, "many">>;
@@ -275,7 +275,6 @@ declare const LessonEntitySchema: z.ZodObject<{
275
275
  durationMinutes: z.ZodDefault<z.ZodNumber>;
276
276
  artifactContract: z.ZodString;
277
277
  }, "strip", z.ZodTypeAny, {
278
- durationMinutes: number;
279
278
  seq: number;
280
279
  phase: string;
281
280
  activityType: string;
@@ -285,6 +284,7 @@ declare const LessonEntitySchema: z.ZodObject<{
285
284
  teacherMove: string;
286
285
  outputEvidence: string;
287
286
  lo: string[];
287
+ durationMinutes: number;
288
288
  artifactContract: string;
289
289
  }, {
290
290
  seq: number;
@@ -317,17 +317,16 @@ declare const LessonEntitySchema: z.ZodObject<{
317
317
  }, "strip", z.ZodTypeAny, {
318
318
  lessonId: string;
319
319
  title: string;
320
+ estimatedDuration: string;
320
321
  learningObjectives: {
321
322
  code: string;
323
+ objective: string;
324
+ evidence: string;
322
325
  successCriteria: string;
323
326
  standardRefs: string[];
324
327
  conceptRefs: string[];
325
- objective: string;
326
- evidence: string;
327
328
  }[];
328
- estimatedDuration: string;
329
329
  activitySequence: {
330
- durationMinutes: number;
331
330
  seq: number;
332
331
  phase: string;
333
332
  activityType: string;
@@ -337,6 +336,7 @@ declare const LessonEntitySchema: z.ZodObject<{
337
336
  teacherMove: string;
338
337
  outputEvidence: string;
339
338
  lo: string[];
339
+ durationMinutes: number;
340
340
  artifactContract: string;
341
341
  }[];
342
342
  assessmentMap: Record<string, string>[];
@@ -349,15 +349,15 @@ declare const LessonEntitySchema: z.ZodObject<{
349
349
  }, {
350
350
  lessonId: string;
351
351
  title: string;
352
+ estimatedDuration?: string | undefined;
352
353
  learningObjectives?: {
353
354
  code: string;
354
- successCriteria: string;
355
355
  objective: string;
356
356
  evidence: string;
357
+ successCriteria: string;
357
358
  standardRefs?: string[] | undefined;
358
359
  conceptRefs?: string[] | undefined;
359
360
  }[] | undefined;
360
- estimatedDuration?: string | undefined;
361
361
  activitySequence?: {
362
362
  seq: number;
363
363
  phase: string;
@@ -1123,6 +1123,13 @@ interface PackingSpec {
1123
1123
  contentBudget: number;
1124
1124
  overheadMinutes: number;
1125
1125
  sessionDurationMinutes: number;
1126
+ /** 2026-09-18 RC-2: cognitive budget — max DISTINCT new concepts per
1127
+ * session (Vygotsky ZPD constant). 0 disables the check. The minute
1128
+ * budget alone packs knowledge-dense sessions (observed: 4 concepts in
1129
+ * one 90m K-12 session); flushing early on this budget is a STRUCTURAL
1130
+ * rule — it counts and cuts, it never reorders across prerequisite
1131
+ * edges (teaching order preserved by construction). */
1132
+ maxNewConceptsPerSession?: number;
1126
1133
  }
1127
1134
  declare function computePackingSpec(constraints: PlanConstraints): PackingSpec;
1128
1135
  interface PackedEntry {
package/dist/index.mjs CHANGED
@@ -4863,9 +4863,9 @@ Evaluate the candidate artifact across these 6 dimensions:
4863
4863
  - 0 pts: Missing critical sections.
4864
4864
 
4865
4865
  5. **Technical & Conceptual Accuracy (15 pts):**
4866
- - 15 pts: Code snippets, logic flows, architectural descriptions, and Mermaid diagrams are conceptually sound and valid. If \`canonicalExposition\` or \`[KNOWLEDGE_EXPOSITION]\` is provided, content strictly adheres to canonical concepts without contradicting definitions or examples.
4866
+ - 15 pts: Code snippets, logic flows, architectural descriptions, and Mermaid diagrams are conceptually sound and valid. Every code identifier uses the REAL standard-library/API spelling of the declared stack (grounded in REFERENCE_PACK / canonical LESSON) \u2014 internal consistency with a glossary term name is NOT evidence of correctness. If \`canonicalExposition\` or \`[KNOWLEDGE_EXPOSITION]\` is provided, content strictly adheres to canonical concepts without contradicting definitions or examples.
4867
4867
  - 8 pts: Minor syntax inaccuracies or unidiomatic code that does not break core concepts.
4868
- - 0 pts: Severe technical hallucinations, broken logic, invalid diagrams, or direct contradiction of canonical exposition knowledge.
4868
+ - 0 pts: Severe technical hallucinations, broken logic, invalid diagrams, invented casing/spelling rules for standard-library identifiers, or direct contradiction of canonical exposition knowledge.
4869
4869
 
4870
4870
  6. **Contract Consistency & Zero-Drift (10 pts):**
4871
4871
  - 10 pts: Satellite artifact strictly adheres to the scope, tech stack, and objectives of Lesson ${lessonId} without introducing unrelated topics. If \`canonicalLessonExcerpt\` is present in candidate JSON, all satellite phases/activities strictly operationalize the master Lesson Flow and Activity Sequence without inventing divergent timelines.
@@ -10196,6 +10196,38 @@ function checkScopeDrift(content, scopedKeywords, tolerance = 0) {
10196
10196
  evidence: drift
10197
10197
  };
10198
10198
  }
10199
+ function checkIdentifierCasing(content, refPack) {
10200
+ if (!refPack || !refPack.trim()) return null;
10201
+ const canonical = /* @__PURE__ */ new Map();
10202
+ const remember = (id) => {
10203
+ if (id.length < 2) return;
10204
+ const key = id.toLowerCase().replace(/_/g, "");
10205
+ if (!canonical.has(key)) canonical.set(key, id);
10206
+ };
10207
+ for (const m of refPack.matchAll(/`([A-Za-z_][A-Za-z0-9_]*)\s*\(/g)) remember(m[1]);
10208
+ for (const m of refPack.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\s*\(/g)) remember(m[1]);
10209
+ for (const m of refPack.matchAll(/`([A-Za-z_][A-Za-z0-9_]*)`/g)) remember(m[1]);
10210
+ if (canonical.size === 0) return null;
10211
+ const RESERVED = /* @__PURE__ */ new Set(["if", "for", "while", "switch", "func", "return", "guard", "catch", "else", "in"]);
10212
+ const violations = [];
10213
+ const fenceRe = /```[a-zA-Z]*\n([\s\S]*?)```/g;
10214
+ for (const fence of content.matchAll(fenceRe)) {
10215
+ for (const m of fence[1].matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\s*\(/g)) {
10216
+ const tok = m[1];
10217
+ if (RESERVED.has(tok.toLowerCase())) continue;
10218
+ const real = canonical.get(tok.toLowerCase().replace(/_/g, ""));
10219
+ if (real && real !== tok && !violations.includes(`${tok} \u2192 ${real}`)) {
10220
+ violations.push(`${tok} \u2192 ${real}`);
10221
+ }
10222
+ }
10223
+ }
10224
+ if (violations.length === 0) return null;
10225
+ return {
10226
+ code: "identifier-casing",
10227
+ detail: `Code d\xF9ng identifier l\u1EC7ch casing so v\u1EDBi REFERENCE_PACK (ngu\u1ED3n s\u1EF1 th\u1EADt k\u1EF9 thu\u1EADt): ${violations.join(", ")}. Identifier trong code PH\u1EA2I copy nguy\xEAn d\u1EA1ng t\u1EEB REFERENCE_PACK \u2014 KH\xD4NG suy ra casing t\u1EEB t\xEAn keyword/concept (ch\xFAng l\xE0 nh\xE3n s\u01B0 ph\u1EA1m, kh\xF4ng ph\u1EA3i API).`,
10228
+ evidence: violations.slice(0, 5)
10229
+ };
10230
+ }
10199
10231
  function validateArtifactDeterministic(input) {
10200
10232
  const issues = [];
10201
10233
  const cjk = scanCjkLeaks(input.content);
@@ -10203,6 +10235,8 @@ function validateArtifactDeterministic(input) {
10203
10235
  if (input.refPack) {
10204
10236
  const ver = checkVersionGroundTruth(input.content, input.refPack);
10205
10237
  if (ver) issues.push(ver);
10238
+ const casing = checkIdentifierCasing(input.content, input.refPack);
10239
+ if (casing) issues.push(casing);
10206
10240
  }
10207
10241
  if (input.scopedKeywords && input.scopedKeywords.length > 0) {
10208
10242
  const scope = checkScopeDrift(input.content, input.scopedKeywords);
@@ -10314,9 +10348,10 @@ function buildSystemPrompt(targetLanguage = "vi", techStack, hardwarePlatform) {
10314
10348
  "Rules:",
10315
10349
  "1. Cover EXACTLY the scoped keywords and concepts \u2014 nothing beyond the session scope.",
10316
10350
  "2. Every Key Term definition must be consistent with the glossary entry provided.",
10317
- "3. Respect each concept depth target (ULO/CIO/SIO) \u2014 do not overshoot.",
10318
- "4. Student-facing only: no teacher instructions, no classroom management text.",
10319
- "5. Output the full markdown document following the provided section skeleton exactly (headers and placeholders preserved).",
10351
+ '3. IDENTIFIER GROUND TRUTH: glossary/keyword names are pedagogical concept labels \u2014 NEVER derive code identifier casing or spelling from them. In code samples, copy identifiers EXACTLY from the REFERENCE_PACK ground truth (e.g. the standard library function is `print` lowercase; "Print" as a topic label is not an API symbol).',
10352
+ "4. Respect each concept depth target (ULO/CIO/SIO) \u2014 do not overshoot.",
10353
+ "5. Student-facing only: no teacher instructions, no classroom management text.",
10354
+ "6. Output the full markdown document following the provided section skeleton exactly (headers and placeholders preserved).",
10320
10355
  domainGuardrails,
10321
10356
  langDirective
10322
10357
  ].join("\n");
@@ -10983,10 +11018,13 @@ function buildUnitGroupings(graph, orderedIds) {
10983
11018
  }
10984
11019
  function computePackingSpec(constraints) {
10985
11020
  const overheadMinutes = Math.round(constraints.session_duration_minutes * constraints.overhead_ratio);
11021
+ const upperAge = constraints.age_band?.[1];
11022
+ const maxNew = upperAge !== void 0 && upperAge > 15 ? MAX_NEW_CONCEPTS_PER_SESSION_ADULT : MAX_NEW_CONCEPTS_PER_SESSION_K12;
10986
11023
  return {
10987
11024
  contentBudget: constraints.session_duration_minutes - overheadMinutes,
10988
11025
  overheadMinutes,
10989
- sessionDurationMinutes: constraints.session_duration_minutes
11026
+ sessionDurationMinutes: constraints.session_duration_minutes,
11027
+ maxNewConceptsPerSession: maxNew
10990
11028
  };
10991
11029
  }
10992
11030
  var filledOf = (s) => s.knowledgeMinutes + s.practiceMinutes;
@@ -11069,6 +11107,15 @@ function packUnitSessions(group, nodeById, spec, warnings) {
11069
11107
  continue;
11070
11108
  }
11071
11109
  const minutes = node.estimated_minutes;
11110
+ if (spec.maxNewConceptsPerSession && spec.maxNewConceptsPerSession > 0 && current.entries.length > 0) {
11111
+ const currentConcepts = new Set(current.nodeIds.flatMap((nid) => nodeById.get(nid)?.concept_codes || []));
11112
+ const incoming = nodeById.get(id)?.concept_codes || [];
11113
+ const wouldAdd = incoming.filter((c) => !currentConcepts.has(c)).length;
11114
+ if (currentConcepts.size + wouldAdd > spec.maxNewConceptsPerSession) {
11115
+ warnings.push(`ZPD pack flush: session ${group.key}#${sessions.length + 1} cut at ${currentConcepts.size} new concepts (budget ${spec.maxNewConceptsPerSession})`);
11116
+ flush();
11117
+ }
11118
+ }
11072
11119
  if (current.entries.length > 0 && filled() + minutes > spec.contentBudget) {
11073
11120
  const displaced = cutBackToCheckpoint(current, nodeById, spec, warnings);
11074
11121
  if (displaced.length > 0) {
@@ -11227,12 +11274,12 @@ function checkSessionZpd(sessionIndex, nodeIds, nodeById, allSeenConcepts, allSe
11227
11274
  const knownKeywords = allKeywords.filter((k) => allSeenKeywords.has(k.toLowerCase()) || entryKw.has(k.toLowerCase()));
11228
11275
  const issues = [];
11229
11276
  let verdict = "OK";
11230
- if (concepts.length > 0 && newConcepts.length > 2) {
11231
- verdict = "TOO_MANY_NEW";
11232
- issues.push(`${newConcepts.length} new concepts exceed ZPD limit (max 2)`);
11233
- } else if (concepts.length === 0 && newKeywords.length > 4) {
11277
+ if (newConcepts.length > MAX_NEW_CONCEPTS_PER_SESSION_K12) {
11234
11278
  verdict = "TOO_MANY_NEW";
11235
- issues.push(`${newKeywords.length} new keywords exceed ZPD limit (max 4)`);
11279
+ issues.push(`${newConcepts.length} new concepts exceed ZPD limit (max ${MAX_NEW_CONCEPTS_PER_SESSION_K12})`);
11280
+ }
11281
+ if (newKeywords.length > 4) {
11282
+ issues.push(`Evidence for judge: ${newKeywords.length} new keywords in session (noisy proxy, not a gate)`);
11236
11283
  }
11237
11284
  if (sessionIndex > 0) {
11238
11285
  if (concepts.length > 1 && knownConcepts.length === 0) {
@@ -27344,6 +27391,7 @@ Your task is to author a canonical, publication-grade learning artifact of type
27344
27391
  ${langDirective}
27345
27392
  ${headingDirective}
27346
27393
  2. NON-MOCK CODE INVARIANT: Any code snippet provided MUST be 100% syntactically valid, idiomatic, and executable without placeholders or fake functions.
27394
+ 2b. IDENTIFIER GROUND TRUTH: Never derive identifier casing/spelling from glossary term or concept names (they are pedagogical labels). Copy identifiers EXACTLY from the canonical LESSON and REFERENCE_PACK ground truth present in the context.
27347
27395
  3. PEDAGOGICAL GROUNDING: Strictly align with the ${pedagogy.toUpperCase()} model, Bloom's Revised Taxonomy, and IEEE/ACM CS2023 guidelines.
27348
27396
  4. SCAFFOLDING LEVEL: "${scaffoldingLevel.toUpperCase()}".${scaffoldingRule}
27349
27397
  5. TARGET AUDIENCE: ${gradeLevel ? `Grade ${gradeLevel}, ` : ""}${targetAge} on ${hwStr}.${deviceRule}${classDynamicsRule}${extraContextRule}
@@ -29903,14 +29951,14 @@ var DeterministicStructuralLinter = class {
29903
29951
  let score = 100;
29904
29952
  for (const s of plan.sessions) {
29905
29953
  if (s.zpd_status?.verdict === "TOO_MANY_NEW") {
29906
- score -= 10;
29954
+ score -= 25;
29907
29955
  findings.push({
29908
29956
  id: `PLAN_TOO_MANY_NEW_${s.id}`,
29909
29957
  dimension: "CONSTRUCTIVE_ALIGNMENT",
29910
- severity: "MINOR",
29958
+ severity: "CRITICAL",
29911
29959
  title: `Cognitive Overload in Session ${s.id}`,
29912
- description: s.zpd_status.issues.join("; ") || `Session introduces too many new concepts/keywords, exceeding ZPD capacity.`,
29913
- remediationAdvice: `Distribute new concepts across multiple sessions or introduce via scaffolding.`,
29960
+ description: s.zpd_status.issues.join("; ") || `Session introduces more new concepts than the ZPD limit allows.`,
29961
+ remediationAdvice: `Split the session: move overflow concepts to a later session (the packer flushes on concept budget automatically).`,
29914
29962
  affectedElement: s.id
29915
29963
  });
29916
29964
  } else if (s.zpd_status?.verdict === "NO_ZPD_BRIDGE") {