@thanh01.pmt/curriculum-kit 1.4.1 → 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,6 +6409,7 @@ 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
6414
  const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
6252
6415
  const sections = parseMarkdownSections(source, slcMap, effectiveArtifactType);
@@ -6266,44 +6429,74 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
6266
6429
  };
6267
6430
  }
6268
6431
  const byCanonical = /* @__PURE__ */ new Map();
6432
+ const byCleanTitle = /* @__PURE__ */ new Map();
6269
6433
  const unmatched = [];
6270
6434
  for (const s of sections) {
6271
6435
  if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
6272
6436
  byCanonical.set(s.canonicalKey, s);
6273
- } else {
6437
+ }
6438
+ const norm = normalizeHeading(s.cleanTitle);
6439
+ if (!byCleanTitle.has(norm)) {
6440
+ byCleanTitle.set(norm, s);
6441
+ }
6442
+ if (!s.canonicalKey) {
6274
6443
  unmatched.push(s);
6275
6444
  }
6276
6445
  }
6277
6446
  const priorities = opts.priorities ?? DEFAULT_LESSON_PRIORITIES;
6278
6447
  const includedSections = [];
6279
6448
  const blocks = [];
6280
- let used = 0;
6449
+ const initialOverhead = metaBlock ? metaBlock.length + 2 : 0;
6450
+ let used = initialOverhead;
6281
6451
  const tryAdd = (heading, body, key) => {
6282
6452
  const trimmedBody = body.trim();
6283
6453
  if (!trimmedBody) return false;
6284
6454
  const block = `## ${heading}
6285
6455
 
6286
6456
  ${trimmedBody}`;
6287
- if (used + block.length > budget && used > 0) return false;
6288
- blocks.push(block);
6289
- used += block.length;
6290
- includedSections.push(key);
6291
- 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;
6292
6484
  };
6293
6485
  blocks.push(metaBlock);
6294
6486
  let sectionAware = false;
6295
6487
  for (const key of priorities) {
6296
- const sec = byCanonical.get(key);
6488
+ const sec = byCanonical.get(key) || byCleanTitle.get(normalizeHeading(key));
6297
6489
  if (!sec) continue;
6298
6490
  sectionAware = true;
6299
6491
  if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
6300
6492
  }
6301
6493
  for (const [key, sec] of byCanonical) {
6302
- if (includedSections.includes(key)) continue;
6494
+ if (includedSections.includes(key) || includedSections.includes(sec.cleanTitle)) continue;
6303
6495
  if (used >= budget) break;
6304
6496
  if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
6305
6497
  }
6306
6498
  for (const sec of unmatched) {
6499
+ if (includedSections.includes(sec.cleanTitle)) continue;
6307
6500
  if (used >= budget) break;
6308
6501
  if (!tryAdd(sec.cleanTitle, sec.body, sec.cleanTitle)) break;
6309
6502
  }
@@ -6311,17 +6504,16 @@ ${trimmedBody}`;
6311
6504
  issues.push("parse:no-canonical-resolution");
6312
6505
  }
6313
6506
  if (priorities.length > 0 && !priorities.some((k) => includedSections.includes(k))) {
6314
- issues.push("parse:no-priority-resolution");
6507
+ issues.push(sections.length === 0 ? "parse:no-sections" : "parse:no-priority-resolution");
6315
6508
  }
6316
6509
  let excerpt = blocks.join("\n\n");
6317
6510
  if (excerpt.length > budget) {
6318
6511
  excerpt = truncateByBudget(excerpt, budget);
6319
6512
  }
6320
- const effectiveMinChars = Math.min(minContentChars, source.length);
6321
- if (excerpt.length - metaBlock.length < effectiveMinChars) {
6513
+ if (excerpt.length - metaBlock.length < minContentChars) {
6322
6514
  issues.push("content:insufficient");
6323
6515
  }
6324
- 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;
6325
6517
  return {
6326
6518
  excerpt,
6327
6519
  verified,
@@ -6381,7 +6573,7 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
6381
6573
  }
6382
6574
  }
6383
6575
  const flush = () => {
6384
- if (!currentHeading && currentBody.length === 0) return;
6576
+ if (!currentHeading) return;
6385
6577
  const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
6386
6578
  const norm = normalizeHeading(cleanTitle);
6387
6579
  const canonicalKey = reverseMap.get(norm) || findCanonicalFuzzy(norm);