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