@thanh01.pmt/curriculum-kit 1.4.0 → 1.4.2

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.
@@ -1111,7 +1111,9 @@ var LessonPlanSchema = zod.z.object({
1111
1111
  name: zod.z.string().optional().default(""),
1112
1112
  description: zod.z.string(),
1113
1113
  bloomLevel: zod.z.string().default("understand"),
1114
- successCriteria: zod.z.string().optional().default("")
1114
+ successCriteria: zod.z.string().optional().default(""),
1115
+ standardRefs: zod.z.array(zod.z.string()).optional(),
1116
+ conceptRefs: zod.z.array(zod.z.string()).optional()
1115
1117
  })).default([]),
1116
1118
  prerequisites: zod.z.string().optional().default(""),
1117
1119
  materialsSummary: zod.z.string().optional().default(""),
@@ -5634,9 +5636,170 @@ var csta_k12_2017_default = {
5634
5636
  ]
5635
5637
  };
5636
5638
 
5639
+ // src/standards/data/acm-ieee-cs2023.json
5640
+ var acm_ieee_cs2023_default = {
5641
+ manifest: {
5642
+ id: "acm-ieee-cs2023",
5643
+ name: "ACM/IEEE-CS/AAAI Computer Science Curricula 2023 (CS2023)",
5644
+ specVersion: "1.0",
5645
+ contentVersion: "2023.1",
5646
+ subject: "computing",
5647
+ languages: ["en"],
5648
+ gradeModel: {
5649
+ type: "grades",
5650
+ range: [9, 16]
5651
+ },
5652
+ provenance: {
5653
+ sourceRef: "ACM/IEEE-CS/AAAI Computer Science Curricula 2023 - cs2023.org",
5654
+ sourceUrl: "https://cs2023.org",
5655
+ license: "ACM / IEEE Computer Society (cited verbatim for curriculum alignment)",
5656
+ importedBy: "platform",
5657
+ importedAt: "2026-09-11T00:00:00.000Z"
5658
+ },
5659
+ trust: "verified"
5660
+ },
5661
+ statements: [
5662
+ {
5663
+ id: "CS2023-SDF-01",
5664
+ gradeBand: [9, 14],
5665
+ texts: {
5666
+ en: "Design, implement, test, and debug programs using basic computation, standard conditional and iterative structures, and functions."
5667
+ },
5668
+ classifications: [
5669
+ { axis: "Knowledge Area", value: "Software Development Fundamentals (SDF)" },
5670
+ { axis: "Core Tier", value: "Tier-1 Core" }
5671
+ ],
5672
+ bloomHint: { process: "Apply" },
5673
+ keywords: ["algorithms", "control structures", "functions", "variables", "debugging", "programming", "implementation"],
5674
+ sourceRef: "CS2023, Software Development Fundamentals, Program Construction",
5675
+ provenance: { method: "source_official" }
5676
+ },
5677
+ {
5678
+ id: "CS2023-SDF-02",
5679
+ gradeBand: [9, 14],
5680
+ texts: {
5681
+ en: "Apply fundamental data structures (arrays, lists, stacks, queues, hash maps) to represent collections of data and solve algorithmic problems."
5682
+ },
5683
+ classifications: [
5684
+ { axis: "Knowledge Area", value: "Software Development Fundamentals (SDF)" },
5685
+ { axis: "Core Tier", value: "Tier-1 Core" }
5686
+ ],
5687
+ bloomHint: { process: "Apply" },
5688
+ keywords: ["data structures", "arrays", "lists", "hash maps", "collections", "stacks", "queues"],
5689
+ sourceRef: "CS2023, Software Development Fundamentals, Fundamental Data Structures",
5690
+ provenance: { method: "source_official" }
5691
+ },
5692
+ {
5693
+ id: "CS2023-AL-01",
5694
+ gradeBand: [10, 16],
5695
+ texts: {
5696
+ en: "Analyze and compare the time and space complexity of fundamental algorithms using asymptotic notation (Big-O)."
5697
+ },
5698
+ classifications: [
5699
+ { axis: "Knowledge Area", value: "Algorithms and Complexity (AL)" },
5700
+ { axis: "Core Tier", value: "Tier-1 Core" }
5701
+ ],
5702
+ bloomHint: { process: "Analyze" },
5703
+ keywords: ["complexity", "big-o", "efficiency", "sorting", "searching", "asymptotic", "runtime"],
5704
+ sourceRef: "CS2023, Algorithms and Complexity, Basic Analysis",
5705
+ provenance: { method: "source_official" }
5706
+ },
5707
+ {
5708
+ id: "CS2023-SE-01",
5709
+ gradeBand: [9, 16],
5710
+ texts: {
5711
+ en: "Decompose complex problems into modular software components applying principles of abstraction, encapsulation, and separation of concerns."
5712
+ },
5713
+ classifications: [
5714
+ { axis: "Knowledge Area", value: "Software Engineering (SE)" },
5715
+ { axis: "Core Tier", value: "Tier-1 Core" }
5716
+ ],
5717
+ bloomHint: { process: "Create" },
5718
+ keywords: ["modularity", "abstraction", "software design", "refactoring", "encapsulation", "architecture"],
5719
+ sourceRef: "CS2023, Software Engineering, Software Design and Architecture",
5720
+ provenance: { method: "source_official" }
5721
+ },
5722
+ {
5723
+ id: "CS2023-SEC-01",
5724
+ gradeBand: [9, 16],
5725
+ texts: {
5726
+ en: "Incorporate defensive programming and fundamental cybersecurity principles (least privilege, input validation, secure data handling) into software development."
5727
+ },
5728
+ classifications: [
5729
+ { axis: "Knowledge Area", value: "Security (SEC)" },
5730
+ { axis: "Core Tier", value: "Tier-1 Core" }
5731
+ ],
5732
+ bloomHint: { process: "Apply" },
5733
+ keywords: ["security", "defensive programming", "input validation", "cybersecurity", "vulnerabilities"],
5734
+ sourceRef: "CS2023, Security, Secure Software Development",
5735
+ provenance: { method: "source_official" }
5736
+ },
5737
+ {
5738
+ id: "CS2023-AI-01",
5739
+ gradeBand: [10, 16],
5740
+ texts: {
5741
+ en: "Formulate machine learning tasks, prepare training and evaluation datasets, and evaluate model performance using standard metrics."
5742
+ },
5743
+ classifications: [
5744
+ { axis: "Knowledge Area", value: "Artificial Intelligence (AI)" },
5745
+ { axis: "Core Tier", value: "Tier-2 Core" }
5746
+ ],
5747
+ bloomHint: { process: "Evaluate" },
5748
+ keywords: ["artificial intelligence", "machine learning", "dataset", "evaluation", "model", "accuracy"],
5749
+ sourceRef: "CS2023, Artificial Intelligence, Machine Learning Fundamentals",
5750
+ provenance: { method: "source_official" }
5751
+ }
5752
+ ],
5753
+ mappings: [
5754
+ {
5755
+ statementId: "CS2023-SDF-01",
5756
+ targetRef: "ontora:PROGRAM_CONSTRUCTION",
5757
+ kind: "covers",
5758
+ confidence: 0.95,
5759
+ provenance: { method: "source_official" }
5760
+ },
5761
+ {
5762
+ statementId: "CS2023-SDF-02",
5763
+ targetRef: "ontora:DATA_STRUCTURES",
5764
+ kind: "covers",
5765
+ confidence: 0.95,
5766
+ provenance: { method: "source_official" }
5767
+ },
5768
+ {
5769
+ statementId: "CS2023-AL-01",
5770
+ targetRef: "ontora:ALGORITHM_COMPLEXITY",
5771
+ kind: "covers",
5772
+ confidence: 0.95,
5773
+ provenance: { method: "source_official" }
5774
+ },
5775
+ {
5776
+ statementId: "CS2023-SE-01",
5777
+ targetRef: "ontora:SOFTWARE_ARCHITECTURE",
5778
+ kind: "covers",
5779
+ confidence: 0.95,
5780
+ provenance: { method: "source_official" }
5781
+ },
5782
+ {
5783
+ statementId: "CS2023-SEC-01",
5784
+ targetRef: "ontora:DEFENSIVE_PROGRAMMING",
5785
+ kind: "covers",
5786
+ confidence: 0.95,
5787
+ provenance: { method: "source_official" }
5788
+ },
5789
+ {
5790
+ statementId: "CS2023-AI-01",
5791
+ targetRef: "ontora:MACHINE_LEARNING",
5792
+ kind: "covers",
5793
+ confidence: 0.95,
5794
+ provenance: { method: "source_official" }
5795
+ }
5796
+ ]
5797
+ };
5798
+
5637
5799
  // src/standards/bundledPacks.ts
5638
5800
  var BUNDLED_PACK_RECORDS = {
5639
- "csta-k12-2017": csta_k12_2017_default
5801
+ "csta-k12-2017": csta_k12_2017_default,
5802
+ "acm-ieee-cs2023": acm_ieee_cs2023_default
5640
5803
  };
5641
5804
  Object.keys(BUNDLED_PACK_RECORDS).sort();
5642
5805
 
@@ -6243,7 +6406,6 @@ var DEFAULT_KX_PRIORITIES = [
6243
6406
  ];
6244
6407
  function buildSectionAwareExcerpt(markdown, opts = {}) {
6245
6408
  const budget = opts.budget ?? 12e3;
6246
- const minContentChars = opts.minContentChars ?? 400;
6247
6409
  const issues = [];
6248
6410
  const source = (markdown || "").trim();
6249
6411
  if (!source) {
@@ -6256,9 +6418,11 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
6256
6418
  tokenEstimate: 0
6257
6419
  };
6258
6420
  }
6421
+ const minContentChars = opts.minContentChars !== void 0 ? opts.minContentChars : Math.min(400, source.length);
6259
6422
  const slcMap = normalizeSlcContract(opts.sectionLanguageContract);
6260
- const sections = parseMarkdownSections(source, slcMap, opts.artifactType);
6261
- const metaBlock = buildMetaBlock(source);
6423
+ const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
6424
+ const sections = parseMarkdownSections(source, slcMap, effectiveArtifactType);
6425
+ const metaBlock = buildMetaBlock(source, effectiveArtifactType);
6262
6426
  if (sections.length === 0) {
6263
6427
  issues.push("parse:no-sections");
6264
6428
  const excerpt2 = truncateByBudget(source, budget);
@@ -6274,44 +6438,74 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
6274
6438
  };
6275
6439
  }
6276
6440
  const byCanonical = /* @__PURE__ */ new Map();
6441
+ const byCleanTitle = /* @__PURE__ */ new Map();
6277
6442
  const unmatched = [];
6278
6443
  for (const s of sections) {
6279
6444
  if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
6280
6445
  byCanonical.set(s.canonicalKey, s);
6281
- } else {
6446
+ }
6447
+ const norm = normalizeHeading(s.cleanTitle);
6448
+ if (!byCleanTitle.has(norm)) {
6449
+ byCleanTitle.set(norm, s);
6450
+ }
6451
+ if (!s.canonicalKey) {
6282
6452
  unmatched.push(s);
6283
6453
  }
6284
6454
  }
6285
6455
  const priorities = opts.priorities ?? DEFAULT_LESSON_PRIORITIES;
6286
6456
  const includedSections = [];
6287
6457
  const blocks = [];
6288
- let used = 0;
6458
+ const initialOverhead = metaBlock ? metaBlock.length + 2 : 0;
6459
+ let used = initialOverhead;
6289
6460
  const tryAdd = (heading, body, key) => {
6290
6461
  const trimmedBody = body.trim();
6291
6462
  if (!trimmedBody) return false;
6292
6463
  const block = `## ${heading}
6293
6464
 
6294
6465
  ${trimmedBody}`;
6295
- if (used + block.length > budget && used > 0) return false;
6296
- blocks.push(block);
6297
- used += block.length;
6298
- includedSections.push(key);
6299
- return true;
6466
+ if (used + block.length <= budget) {
6467
+ blocks.push(block);
6468
+ used += block.length;
6469
+ includedSections.push(key);
6470
+ return true;
6471
+ }
6472
+ if (includedSections.length === 0 && budget >= minContentChars) {
6473
+ const headingOverhead = `## ${heading}
6474
+
6475
+ `.length;
6476
+ const remaining = budget - used;
6477
+ if (remaining > headingOverhead + 50) {
6478
+ const allowedBody = remaining - headingOverhead;
6479
+ const truncated = truncateByBudget(trimmedBody, allowedBody).trim();
6480
+ if (truncated.length > 0) {
6481
+ const partialBlock = `## ${heading}
6482
+
6483
+ ${truncated}`;
6484
+ blocks.push(partialBlock);
6485
+ used += partialBlock.length;
6486
+ includedSections.push(key);
6487
+ issues.push(`section:truncated:${key}`);
6488
+ return true;
6489
+ }
6490
+ }
6491
+ }
6492
+ return false;
6300
6493
  };
6301
6494
  blocks.push(metaBlock);
6302
6495
  let sectionAware = false;
6303
6496
  for (const key of priorities) {
6304
- const sec = byCanonical.get(key);
6497
+ const sec = byCanonical.get(key) || byCleanTitle.get(normalizeHeading(key));
6305
6498
  if (!sec) continue;
6306
6499
  sectionAware = true;
6307
6500
  if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
6308
6501
  }
6309
6502
  for (const [key, sec] of byCanonical) {
6310
- if (includedSections.includes(key)) continue;
6503
+ if (includedSections.includes(key) || includedSections.includes(sec.cleanTitle)) continue;
6311
6504
  if (used >= budget) break;
6312
6505
  if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
6313
6506
  }
6314
6507
  for (const sec of unmatched) {
6508
+ if (includedSections.includes(sec.cleanTitle)) continue;
6315
6509
  if (used >= budget) break;
6316
6510
  if (!tryAdd(sec.cleanTitle, sec.body, sec.cleanTitle)) break;
6317
6511
  }
@@ -6319,17 +6513,16 @@ ${trimmedBody}`;
6319
6513
  issues.push("parse:no-canonical-resolution");
6320
6514
  }
6321
6515
  if (priorities.length > 0 && !priorities.some((k) => includedSections.includes(k))) {
6322
- issues.push("parse:no-priority-resolution");
6516
+ issues.push(sections.length === 0 ? "parse:no-sections" : "parse:no-priority-resolution");
6323
6517
  }
6324
6518
  let excerpt = blocks.join("\n\n");
6325
6519
  if (excerpt.length > budget) {
6326
6520
  excerpt = truncateByBudget(excerpt, budget);
6327
6521
  }
6328
- const effectiveMinChars = Math.min(minContentChars, source.length);
6329
- if (excerpt.length - metaBlock.length < effectiveMinChars) {
6522
+ if (excerpt.length - metaBlock.length < minContentChars) {
6330
6523
  issues.push("content:insufficient");
6331
6524
  }
6332
- const verified = !issues.includes("parse:no-priority-resolution") && !issues.includes("parse:no-canonical-resolution") && excerpt.length - metaBlock.length >= effectiveMinChars;
6525
+ const verified = !issues.includes("parse:no-priority-resolution") && !issues.includes("parse:no-canonical-resolution") && excerpt.length - metaBlock.length >= minContentChars;
6333
6526
  return {
6334
6527
  excerpt,
6335
6528
  verified,
@@ -6389,7 +6582,7 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
6389
6582
  }
6390
6583
  }
6391
6584
  const flush = () => {
6392
- if (!currentHeading && currentBody.length === 0) return;
6585
+ if (!currentHeading) return;
6393
6586
  const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
6394
6587
  const norm = normalizeHeading(cleanTitle);
6395
6588
  const canonicalKey = reverseMap.get(norm) || findCanonicalFuzzy(norm);
@@ -6449,7 +6642,7 @@ function truncateByBudget(source, budget) {
6449
6642
  if (fenceCount % 2 === 1) cut += "\n```";
6450
6643
  return cut;
6451
6644
  }
6452
- function buildMetaBlock(source) {
6645
+ function buildMetaBlock(source, artifactType) {
6453
6646
  const fm = source.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
6454
6647
  const pick = (key) => {
6455
6648
  if (!fm) return "";
@@ -6458,9 +6651,17 @@ function buildMetaBlock(source) {
6458
6651
  };
6459
6652
  const id = pick("id");
6460
6653
  const title = pick("title");
6461
- const type = pick("type");
6654
+ const type = pick("type") || artifactType || "";
6462
6655
  return `<!-- SOURCE: ${type || "ARTIFACT"} | ${id || "unknown"}${title ? ` \u2014 ${title}` : ""} (section-aware excerpt; canonical knowledge, do not contradict) -->`;
6463
6656
  }
6657
+ function deriveArtifactTypeFromFileName(fileName) {
6658
+ if (!fileName) return void 0;
6659
+ const base = fileName.replace(/\.md$/i, "");
6660
+ const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|SECTION_LANGUAGE_CONTRACT|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
6661
+ if (multiWord) return multiWord[1].toUpperCase();
6662
+ const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
6663
+ return token ? token[1] : void 0;
6664
+ }
6464
6665
  init_errors();
6465
6666
 
6466
6667
  // src/services/languageDirective.ts