@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.
- package/LICENSE +21 -0
- package/dist/ai/index.cjs +3 -1
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +4 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.mjs +3 -1
- package/dist/ai/index.mjs.map +1 -1
- package/dist/index.cjs +458 -135
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.mjs +456 -136
- package/dist/index.mjs.map +1 -1
- package/dist/pipeline/index.cjs +3 -1
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.mjs +3 -1
- package/dist/pipeline/index.mjs.map +1 -1
- package/dist/schemas/index.cjs +3 -1
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +20 -0
- package/dist/schemas/index.d.ts +20 -0
- package/dist/schemas/index.mjs +3 -1
- package/dist/schemas/index.mjs.map +1 -1
- package/dist/standards/index.cjs +195 -1
- package/dist/standards/index.cjs.map +1 -1
- package/dist/standards/index.d.cts +20 -1
- package/dist/standards/index.d.ts +20 -1
- package/dist/standards/index.mjs +193 -2
- package/dist/standards/index.mjs.map +1 -1
- package/dist/workflow/index.cjs +209 -17
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.mjs +209 -17
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +21 -22
package/dist/index.cjs
CHANGED
|
@@ -1312,7 +1312,9 @@ var LessonPlanSchema = zod.z.object({
|
|
|
1312
1312
|
name: zod.z.string().optional().default(""),
|
|
1313
1313
|
description: zod.z.string(),
|
|
1314
1314
|
bloomLevel: zod.z.string().default("understand"),
|
|
1315
|
-
successCriteria: zod.z.string().optional().default("")
|
|
1315
|
+
successCriteria: zod.z.string().optional().default(""),
|
|
1316
|
+
standardRefs: zod.z.array(zod.z.string()).optional(),
|
|
1317
|
+
conceptRefs: zod.z.array(zod.z.string()).optional()
|
|
1316
1318
|
})).default([]),
|
|
1317
1319
|
prerequisites: zod.z.string().optional().default(""),
|
|
1318
1320
|
materialsSummary: zod.z.string().optional().default(""),
|
|
@@ -9827,7 +9829,6 @@ var DEFAULT_KX_PRIORITIES = [
|
|
|
9827
9829
|
];
|
|
9828
9830
|
function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
9829
9831
|
const budget = opts.budget ?? 12e3;
|
|
9830
|
-
const minContentChars = opts.minContentChars ?? 400;
|
|
9831
9832
|
const issues = [];
|
|
9832
9833
|
const source = (markdown || "").trim();
|
|
9833
9834
|
if (!source) {
|
|
@@ -9840,6 +9841,7 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
9840
9841
|
tokenEstimate: 0
|
|
9841
9842
|
};
|
|
9842
9843
|
}
|
|
9844
|
+
const minContentChars = opts.minContentChars !== void 0 ? opts.minContentChars : Math.min(400, source.length);
|
|
9843
9845
|
const slcMap = normalizeSlcContract(opts.sectionLanguageContract);
|
|
9844
9846
|
const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
|
|
9845
9847
|
const sections = parseMarkdownSections(source, slcMap, effectiveArtifactType);
|
|
@@ -9859,44 +9861,74 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
9859
9861
|
};
|
|
9860
9862
|
}
|
|
9861
9863
|
const byCanonical = /* @__PURE__ */ new Map();
|
|
9864
|
+
const byCleanTitle = /* @__PURE__ */ new Map();
|
|
9862
9865
|
const unmatched = [];
|
|
9863
9866
|
for (const s of sections) {
|
|
9864
9867
|
if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
|
|
9865
9868
|
byCanonical.set(s.canonicalKey, s);
|
|
9866
|
-
}
|
|
9869
|
+
}
|
|
9870
|
+
const norm = normalizeHeading(s.cleanTitle);
|
|
9871
|
+
if (!byCleanTitle.has(norm)) {
|
|
9872
|
+
byCleanTitle.set(norm, s);
|
|
9873
|
+
}
|
|
9874
|
+
if (!s.canonicalKey) {
|
|
9867
9875
|
unmatched.push(s);
|
|
9868
9876
|
}
|
|
9869
9877
|
}
|
|
9870
9878
|
const priorities = opts.priorities ?? DEFAULT_LESSON_PRIORITIES;
|
|
9871
9879
|
const includedSections = [];
|
|
9872
9880
|
const blocks = [];
|
|
9873
|
-
|
|
9881
|
+
const initialOverhead = metaBlock ? metaBlock.length + 2 : 0;
|
|
9882
|
+
let used = initialOverhead;
|
|
9874
9883
|
const tryAdd = (heading, body, key) => {
|
|
9875
9884
|
const trimmedBody = body.trim();
|
|
9876
9885
|
if (!trimmedBody) return false;
|
|
9877
9886
|
const block = `## ${heading}
|
|
9878
9887
|
|
|
9879
9888
|
${trimmedBody}`;
|
|
9880
|
-
if (used + block.length
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
9889
|
+
if (used + block.length <= budget) {
|
|
9890
|
+
blocks.push(block);
|
|
9891
|
+
used += block.length;
|
|
9892
|
+
includedSections.push(key);
|
|
9893
|
+
return true;
|
|
9894
|
+
}
|
|
9895
|
+
if (includedSections.length === 0 && budget >= minContentChars) {
|
|
9896
|
+
const headingOverhead = `## ${heading}
|
|
9897
|
+
|
|
9898
|
+
`.length;
|
|
9899
|
+
const remaining = budget - used;
|
|
9900
|
+
if (remaining > headingOverhead + 50) {
|
|
9901
|
+
const allowedBody = remaining - headingOverhead;
|
|
9902
|
+
const truncated = truncateByBudget(trimmedBody, allowedBody).trim();
|
|
9903
|
+
if (truncated.length > 0) {
|
|
9904
|
+
const partialBlock = `## ${heading}
|
|
9905
|
+
|
|
9906
|
+
${truncated}`;
|
|
9907
|
+
blocks.push(partialBlock);
|
|
9908
|
+
used += partialBlock.length;
|
|
9909
|
+
includedSections.push(key);
|
|
9910
|
+
issues.push(`section:truncated:${key}`);
|
|
9911
|
+
return true;
|
|
9912
|
+
}
|
|
9913
|
+
}
|
|
9914
|
+
}
|
|
9915
|
+
return false;
|
|
9885
9916
|
};
|
|
9886
9917
|
blocks.push(metaBlock);
|
|
9887
9918
|
let sectionAware = false;
|
|
9888
9919
|
for (const key of priorities) {
|
|
9889
|
-
const sec = byCanonical.get(key);
|
|
9920
|
+
const sec = byCanonical.get(key) || byCleanTitle.get(normalizeHeading(key));
|
|
9890
9921
|
if (!sec) continue;
|
|
9891
9922
|
sectionAware = true;
|
|
9892
9923
|
if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
|
|
9893
9924
|
}
|
|
9894
9925
|
for (const [key, sec] of byCanonical) {
|
|
9895
|
-
if (includedSections.includes(key)) continue;
|
|
9926
|
+
if (includedSections.includes(key) || includedSections.includes(sec.cleanTitle)) continue;
|
|
9896
9927
|
if (used >= budget) break;
|
|
9897
9928
|
if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
|
|
9898
9929
|
}
|
|
9899
9930
|
for (const sec of unmatched) {
|
|
9931
|
+
if (includedSections.includes(sec.cleanTitle)) continue;
|
|
9900
9932
|
if (used >= budget) break;
|
|
9901
9933
|
if (!tryAdd(sec.cleanTitle, sec.body, sec.cleanTitle)) break;
|
|
9902
9934
|
}
|
|
@@ -9904,17 +9936,16 @@ ${trimmedBody}`;
|
|
|
9904
9936
|
issues.push("parse:no-canonical-resolution");
|
|
9905
9937
|
}
|
|
9906
9938
|
if (priorities.length > 0 && !priorities.some((k) => includedSections.includes(k))) {
|
|
9907
|
-
issues.push("parse:no-priority-resolution");
|
|
9939
|
+
issues.push(sections.length === 0 ? "parse:no-sections" : "parse:no-priority-resolution");
|
|
9908
9940
|
}
|
|
9909
9941
|
let excerpt = blocks.join("\n\n");
|
|
9910
9942
|
if (excerpt.length > budget) {
|
|
9911
9943
|
excerpt = truncateByBudget(excerpt, budget);
|
|
9912
9944
|
}
|
|
9913
|
-
|
|
9914
|
-
if (excerpt.length - metaBlock.length < effectiveMinChars) {
|
|
9945
|
+
if (excerpt.length - metaBlock.length < minContentChars) {
|
|
9915
9946
|
issues.push("content:insufficient");
|
|
9916
9947
|
}
|
|
9917
|
-
const verified = !issues.includes("parse:no-priority-resolution") && !issues.includes("parse:no-canonical-resolution") && excerpt.length - metaBlock.length >=
|
|
9948
|
+
const verified = !issues.includes("parse:no-priority-resolution") && !issues.includes("parse:no-canonical-resolution") && excerpt.length - metaBlock.length >= minContentChars;
|
|
9918
9949
|
return {
|
|
9919
9950
|
excerpt,
|
|
9920
9951
|
verified,
|
|
@@ -9974,7 +10005,7 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
|
9974
10005
|
}
|
|
9975
10006
|
}
|
|
9976
10007
|
const flush = () => {
|
|
9977
|
-
if (!currentHeading
|
|
10008
|
+
if (!currentHeading) return;
|
|
9978
10009
|
const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
|
|
9979
10010
|
const norm = normalizeHeading(cleanTitle);
|
|
9980
10011
|
const canonicalKey = reverseMap.get(norm) || findCanonicalFuzzy(norm);
|
|
@@ -10957,6 +10988,120 @@ function buildStandardsContext(input) {
|
|
|
10957
10988
|
const selected = selectStatementsForLesson(input);
|
|
10958
10989
|
return { block: buildStandardsContextBlock(selected, { language: input.language }), selected };
|
|
10959
10990
|
}
|
|
10991
|
+
|
|
10992
|
+
// src/standards/standardsCoverageGate.ts
|
|
10993
|
+
function resolveStatementRef(ref, packs) {
|
|
10994
|
+
const [head, ...rest] = ref.split(":");
|
|
10995
|
+
const candidatePacks = rest.length > 0 ? packs.filter((p) => p.manifest.id === head) : packs;
|
|
10996
|
+
const statementId = rest.length > 0 ? rest.join(":") : ref;
|
|
10997
|
+
for (const p of candidatePacks) {
|
|
10998
|
+
if (p.statements.some((s) => s.id === statementId)) return { pack: p, statementId };
|
|
10999
|
+
}
|
|
11000
|
+
return null;
|
|
11001
|
+
}
|
|
11002
|
+
function evaluateStandardsCoverage(input) {
|
|
11003
|
+
const rows = [];
|
|
11004
|
+
const aoToLo = /* @__PURE__ */ new Map();
|
|
11005
|
+
for (const ao of input.assessmentObjectives ?? []) aoToLo.set(ao.aoCode, ao.alignedLO);
|
|
11006
|
+
const loToRefs = /* @__PURE__ */ new Map();
|
|
11007
|
+
for (const lo of input.objectives) {
|
|
11008
|
+
loToRefs.set(lo.code, new Set(lo.standardRefs ?? []));
|
|
11009
|
+
}
|
|
11010
|
+
const taughtLOs = /* @__PURE__ */ new Set();
|
|
11011
|
+
for (const act of input.activities ?? []) for (const lo of act.lo) taughtLOs.add(lo);
|
|
11012
|
+
const assessedLOs = /* @__PURE__ */ new Set();
|
|
11013
|
+
for (const q of input.quizQuestions) {
|
|
11014
|
+
if (q.alignedLO) assessedLOs.add(q.alignedLO);
|
|
11015
|
+
if (q.alignedAO) {
|
|
11016
|
+
const lo = aoToLo.get(q.alignedAO);
|
|
11017
|
+
if (lo) assessedLOs.add(lo);
|
|
11018
|
+
}
|
|
11019
|
+
}
|
|
11020
|
+
for (const pack of input.packs) {
|
|
11021
|
+
const mappingByStatement = /* @__PURE__ */ new Map();
|
|
11022
|
+
for (const m of pack.mappings ?? []) {
|
|
11023
|
+
const prev = mappingByStatement.get(m.statementId);
|
|
11024
|
+
if (!prev || prev !== "covers" && m.kind === "covers" || prev === "extends" && m.kind !== "extends") {
|
|
11025
|
+
mappingByStatement.set(m.statementId, m.kind);
|
|
11026
|
+
}
|
|
11027
|
+
}
|
|
11028
|
+
for (const statement of pack.statements) {
|
|
11029
|
+
const refFull = `${pack.manifest.id}:${statement.id}`;
|
|
11030
|
+
const issues = [];
|
|
11031
|
+
const los = input.objectives.filter((lo) => (lo.standardRefs ?? []).some((r) => r === statement.id || r === refFull)).map((lo) => lo.code);
|
|
11032
|
+
const kind = mappingByStatement.get(statement.id);
|
|
11033
|
+
const hasMapping = kind !== void 0;
|
|
11034
|
+
const isComplianceRelevant = kind === "covers";
|
|
11035
|
+
const hasActivity = los.some((lo) => taughtLOs.has(lo));
|
|
11036
|
+
const hasAssessment = los.some((lo) => assessedLOs.has(lo));
|
|
11037
|
+
let status;
|
|
11038
|
+
if (!hasMapping) status = "UNMAPPED";
|
|
11039
|
+
else if (!isComplianceRelevant) status = "PARTIAL";
|
|
11040
|
+
else if (los.length > 0 && hasActivity && hasAssessment) status = "COVERED";
|
|
11041
|
+
else status = "UNCOVERED";
|
|
11042
|
+
if (status === "UNCOVERED") {
|
|
11043
|
+
if (los.length === 0) issues.push("No learning objective anchors this statement (missing standardRefs).");
|
|
11044
|
+
else {
|
|
11045
|
+
if (!hasActivity) issues.push(`Anchored LO(s) ${los.join(", ")} have no activity in lesson flow.`);
|
|
11046
|
+
if (!hasAssessment) issues.push(`Anchored LO(s) ${los.join(", ")} are not measured by any quiz question.`);
|
|
11047
|
+
}
|
|
11048
|
+
}
|
|
11049
|
+
rows.push({
|
|
11050
|
+
packId: pack.manifest.id,
|
|
11051
|
+
statementId: statement.id,
|
|
11052
|
+
statementText: Object.values(statement.texts)[0] ?? "",
|
|
11053
|
+
status,
|
|
11054
|
+
objectives: los,
|
|
11055
|
+
hasActivity,
|
|
11056
|
+
hasAssessment,
|
|
11057
|
+
issues
|
|
11058
|
+
});
|
|
11059
|
+
}
|
|
11060
|
+
}
|
|
11061
|
+
for (const lo of input.objectives) {
|
|
11062
|
+
for (const r of lo.standardRefs ?? []) {
|
|
11063
|
+
if (!resolveStatementRef(r, input.packs)) {
|
|
11064
|
+
rows.push({
|
|
11065
|
+
packId: "(unresolved)",
|
|
11066
|
+
statementId: r,
|
|
11067
|
+
statementText: "",
|
|
11068
|
+
status: "UNCOVERED",
|
|
11069
|
+
objectives: [lo.code],
|
|
11070
|
+
hasActivity: false,
|
|
11071
|
+
hasAssessment: false,
|
|
11072
|
+
issues: [`standardRef "${r}" does not exist in any adopted pack \u2014 likely a hallucinated or stale ID`]
|
|
11073
|
+
});
|
|
11074
|
+
}
|
|
11075
|
+
}
|
|
11076
|
+
}
|
|
11077
|
+
const complianceRows = rows.filter((r) => r.status !== "UNMAPPED" && r.status !== "PARTIAL");
|
|
11078
|
+
const covered = complianceRows.filter((r) => r.status === "COVERED").length;
|
|
11079
|
+
const coveragePct = complianceRows.length === 0 ? 100 : Math.round(covered / complianceRows.length * 100);
|
|
11080
|
+
const unresolvedCount = rows.filter((r) => r.packId === "(unresolved)").length;
|
|
11081
|
+
const verdict = unresolvedCount > 0 || coveragePct < 60 ? "FAIL" : coveragePct < 100 ? "WARN" : "PASS";
|
|
11082
|
+
const lines = [
|
|
11083
|
+
"# Standards Coverage Report",
|
|
11084
|
+
"",
|
|
11085
|
+
`- Verdict: **${verdict}**`,
|
|
11086
|
+
`- Compliance coverage: **${coveragePct}%** (${covered}/${complianceRows.length} "covers" statements fully taught + assessed)`,
|
|
11087
|
+
`- Unresolved standardRefs: ${unresolvedCount}`,
|
|
11088
|
+
"",
|
|
11089
|
+
"| Pack | Statement | Status | LOs | Activity | Assessment |",
|
|
11090
|
+
"|---|---|---|---|---|---|",
|
|
11091
|
+
...rows.map(
|
|
11092
|
+
(r) => `|${r.packId}|${r.statementId}|${r.status}|${r.objectives.join(", ") || "\u2014"}|${r.hasActivity ? "\u2713" : "\u2717"}|${r.hasAssessment ? "\u2713" : "\u2717"}|`
|
|
11093
|
+
)
|
|
11094
|
+
];
|
|
11095
|
+
const issueLines = rows.filter((r) => r.issues.length > 0).flatMap((r) => r.issues.map((i) => `- [${r.packId}:${r.statementId}] ${i}`));
|
|
11096
|
+
if (issueLines.length > 0) lines.push("", "## Issues", ...issueLines);
|
|
11097
|
+
return {
|
|
11098
|
+
verdict,
|
|
11099
|
+
coveragePct,
|
|
11100
|
+
rows,
|
|
11101
|
+
summary: `Standards coverage ${coveragePct}% \u2014 verdict ${verdict}`,
|
|
11102
|
+
rawMarkdownReport: lines.join("\n")
|
|
11103
|
+
};
|
|
11104
|
+
}
|
|
10960
11105
|
var BloomHintSchema = zod.z.object({
|
|
10961
11106
|
process: zod.z.enum(["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"]).describe("Cognitive process axis"),
|
|
10962
11107
|
knowledge: zod.z.enum(["FACTUAL", "CONCEPTUAL", "PROCEDURAL", "METACOGNITIVE"]).optional().describe("Knowledge dimension axis (optional \u2014 most source standards do not tag it)")
|
|
@@ -11392,9 +11537,170 @@ var csta_k12_2017_default = {
|
|
|
11392
11537
|
]
|
|
11393
11538
|
};
|
|
11394
11539
|
|
|
11540
|
+
// src/standards/data/acm-ieee-cs2023.json
|
|
11541
|
+
var acm_ieee_cs2023_default = {
|
|
11542
|
+
manifest: {
|
|
11543
|
+
id: "acm-ieee-cs2023",
|
|
11544
|
+
name: "ACM/IEEE-CS/AAAI Computer Science Curricula 2023 (CS2023)",
|
|
11545
|
+
specVersion: "1.0",
|
|
11546
|
+
contentVersion: "2023.1",
|
|
11547
|
+
subject: "computing",
|
|
11548
|
+
languages: ["en"],
|
|
11549
|
+
gradeModel: {
|
|
11550
|
+
type: "grades",
|
|
11551
|
+
range: [9, 16]
|
|
11552
|
+
},
|
|
11553
|
+
provenance: {
|
|
11554
|
+
sourceRef: "ACM/IEEE-CS/AAAI Computer Science Curricula 2023 - cs2023.org",
|
|
11555
|
+
sourceUrl: "https://cs2023.org",
|
|
11556
|
+
license: "ACM / IEEE Computer Society (cited verbatim for curriculum alignment)",
|
|
11557
|
+
importedBy: "platform",
|
|
11558
|
+
importedAt: "2026-09-11T00:00:00.000Z"
|
|
11559
|
+
},
|
|
11560
|
+
trust: "verified"
|
|
11561
|
+
},
|
|
11562
|
+
statements: [
|
|
11563
|
+
{
|
|
11564
|
+
id: "CS2023-SDF-01",
|
|
11565
|
+
gradeBand: [9, 14],
|
|
11566
|
+
texts: {
|
|
11567
|
+
en: "Design, implement, test, and debug programs using basic computation, standard conditional and iterative structures, and functions."
|
|
11568
|
+
},
|
|
11569
|
+
classifications: [
|
|
11570
|
+
{ axis: "Knowledge Area", value: "Software Development Fundamentals (SDF)" },
|
|
11571
|
+
{ axis: "Core Tier", value: "Tier-1 Core" }
|
|
11572
|
+
],
|
|
11573
|
+
bloomHint: { process: "Apply" },
|
|
11574
|
+
keywords: ["algorithms", "control structures", "functions", "variables", "debugging", "programming", "implementation"],
|
|
11575
|
+
sourceRef: "CS2023, Software Development Fundamentals, Program Construction",
|
|
11576
|
+
provenance: { method: "source_official" }
|
|
11577
|
+
},
|
|
11578
|
+
{
|
|
11579
|
+
id: "CS2023-SDF-02",
|
|
11580
|
+
gradeBand: [9, 14],
|
|
11581
|
+
texts: {
|
|
11582
|
+
en: "Apply fundamental data structures (arrays, lists, stacks, queues, hash maps) to represent collections of data and solve algorithmic problems."
|
|
11583
|
+
},
|
|
11584
|
+
classifications: [
|
|
11585
|
+
{ axis: "Knowledge Area", value: "Software Development Fundamentals (SDF)" },
|
|
11586
|
+
{ axis: "Core Tier", value: "Tier-1 Core" }
|
|
11587
|
+
],
|
|
11588
|
+
bloomHint: { process: "Apply" },
|
|
11589
|
+
keywords: ["data structures", "arrays", "lists", "hash maps", "collections", "stacks", "queues"],
|
|
11590
|
+
sourceRef: "CS2023, Software Development Fundamentals, Fundamental Data Structures",
|
|
11591
|
+
provenance: { method: "source_official" }
|
|
11592
|
+
},
|
|
11593
|
+
{
|
|
11594
|
+
id: "CS2023-AL-01",
|
|
11595
|
+
gradeBand: [10, 16],
|
|
11596
|
+
texts: {
|
|
11597
|
+
en: "Analyze and compare the time and space complexity of fundamental algorithms using asymptotic notation (Big-O)."
|
|
11598
|
+
},
|
|
11599
|
+
classifications: [
|
|
11600
|
+
{ axis: "Knowledge Area", value: "Algorithms and Complexity (AL)" },
|
|
11601
|
+
{ axis: "Core Tier", value: "Tier-1 Core" }
|
|
11602
|
+
],
|
|
11603
|
+
bloomHint: { process: "Analyze" },
|
|
11604
|
+
keywords: ["complexity", "big-o", "efficiency", "sorting", "searching", "asymptotic", "runtime"],
|
|
11605
|
+
sourceRef: "CS2023, Algorithms and Complexity, Basic Analysis",
|
|
11606
|
+
provenance: { method: "source_official" }
|
|
11607
|
+
},
|
|
11608
|
+
{
|
|
11609
|
+
id: "CS2023-SE-01",
|
|
11610
|
+
gradeBand: [9, 16],
|
|
11611
|
+
texts: {
|
|
11612
|
+
en: "Decompose complex problems into modular software components applying principles of abstraction, encapsulation, and separation of concerns."
|
|
11613
|
+
},
|
|
11614
|
+
classifications: [
|
|
11615
|
+
{ axis: "Knowledge Area", value: "Software Engineering (SE)" },
|
|
11616
|
+
{ axis: "Core Tier", value: "Tier-1 Core" }
|
|
11617
|
+
],
|
|
11618
|
+
bloomHint: { process: "Create" },
|
|
11619
|
+
keywords: ["modularity", "abstraction", "software design", "refactoring", "encapsulation", "architecture"],
|
|
11620
|
+
sourceRef: "CS2023, Software Engineering, Software Design and Architecture",
|
|
11621
|
+
provenance: { method: "source_official" }
|
|
11622
|
+
},
|
|
11623
|
+
{
|
|
11624
|
+
id: "CS2023-SEC-01",
|
|
11625
|
+
gradeBand: [9, 16],
|
|
11626
|
+
texts: {
|
|
11627
|
+
en: "Incorporate defensive programming and fundamental cybersecurity principles (least privilege, input validation, secure data handling) into software development."
|
|
11628
|
+
},
|
|
11629
|
+
classifications: [
|
|
11630
|
+
{ axis: "Knowledge Area", value: "Security (SEC)" },
|
|
11631
|
+
{ axis: "Core Tier", value: "Tier-1 Core" }
|
|
11632
|
+
],
|
|
11633
|
+
bloomHint: { process: "Apply" },
|
|
11634
|
+
keywords: ["security", "defensive programming", "input validation", "cybersecurity", "vulnerabilities"],
|
|
11635
|
+
sourceRef: "CS2023, Security, Secure Software Development",
|
|
11636
|
+
provenance: { method: "source_official" }
|
|
11637
|
+
},
|
|
11638
|
+
{
|
|
11639
|
+
id: "CS2023-AI-01",
|
|
11640
|
+
gradeBand: [10, 16],
|
|
11641
|
+
texts: {
|
|
11642
|
+
en: "Formulate machine learning tasks, prepare training and evaluation datasets, and evaluate model performance using standard metrics."
|
|
11643
|
+
},
|
|
11644
|
+
classifications: [
|
|
11645
|
+
{ axis: "Knowledge Area", value: "Artificial Intelligence (AI)" },
|
|
11646
|
+
{ axis: "Core Tier", value: "Tier-2 Core" }
|
|
11647
|
+
],
|
|
11648
|
+
bloomHint: { process: "Evaluate" },
|
|
11649
|
+
keywords: ["artificial intelligence", "machine learning", "dataset", "evaluation", "model", "accuracy"],
|
|
11650
|
+
sourceRef: "CS2023, Artificial Intelligence, Machine Learning Fundamentals",
|
|
11651
|
+
provenance: { method: "source_official" }
|
|
11652
|
+
}
|
|
11653
|
+
],
|
|
11654
|
+
mappings: [
|
|
11655
|
+
{
|
|
11656
|
+
statementId: "CS2023-SDF-01",
|
|
11657
|
+
targetRef: "ontora:PROGRAM_CONSTRUCTION",
|
|
11658
|
+
kind: "covers",
|
|
11659
|
+
confidence: 0.95,
|
|
11660
|
+
provenance: { method: "source_official" }
|
|
11661
|
+
},
|
|
11662
|
+
{
|
|
11663
|
+
statementId: "CS2023-SDF-02",
|
|
11664
|
+
targetRef: "ontora:DATA_STRUCTURES",
|
|
11665
|
+
kind: "covers",
|
|
11666
|
+
confidence: 0.95,
|
|
11667
|
+
provenance: { method: "source_official" }
|
|
11668
|
+
},
|
|
11669
|
+
{
|
|
11670
|
+
statementId: "CS2023-AL-01",
|
|
11671
|
+
targetRef: "ontora:ALGORITHM_COMPLEXITY",
|
|
11672
|
+
kind: "covers",
|
|
11673
|
+
confidence: 0.95,
|
|
11674
|
+
provenance: { method: "source_official" }
|
|
11675
|
+
},
|
|
11676
|
+
{
|
|
11677
|
+
statementId: "CS2023-SE-01",
|
|
11678
|
+
targetRef: "ontora:SOFTWARE_ARCHITECTURE",
|
|
11679
|
+
kind: "covers",
|
|
11680
|
+
confidence: 0.95,
|
|
11681
|
+
provenance: { method: "source_official" }
|
|
11682
|
+
},
|
|
11683
|
+
{
|
|
11684
|
+
statementId: "CS2023-SEC-01",
|
|
11685
|
+
targetRef: "ontora:DEFENSIVE_PROGRAMMING",
|
|
11686
|
+
kind: "covers",
|
|
11687
|
+
confidence: 0.95,
|
|
11688
|
+
provenance: { method: "source_official" }
|
|
11689
|
+
},
|
|
11690
|
+
{
|
|
11691
|
+
statementId: "CS2023-AI-01",
|
|
11692
|
+
targetRef: "ontora:MACHINE_LEARNING",
|
|
11693
|
+
kind: "covers",
|
|
11694
|
+
confidence: 0.95,
|
|
11695
|
+
provenance: { method: "source_official" }
|
|
11696
|
+
}
|
|
11697
|
+
]
|
|
11698
|
+
};
|
|
11699
|
+
|
|
11395
11700
|
// src/standards/bundledPacks.ts
|
|
11396
11701
|
var BUNDLED_PACK_RECORDS = {
|
|
11397
|
-
"csta-k12-2017": csta_k12_2017_default
|
|
11702
|
+
"csta-k12-2017": csta_k12_2017_default,
|
|
11703
|
+
"acm-ieee-cs2023": acm_ieee_cs2023_default
|
|
11398
11704
|
};
|
|
11399
11705
|
var BUNDLED_STANDARDS_PACK_IDS = Object.keys(BUNDLED_PACK_RECORDS).sort();
|
|
11400
11706
|
var parsedPackCache = /* @__PURE__ */ new Map();
|
|
@@ -11421,6 +11727,36 @@ function resolveStandardsPacks(packIds) {
|
|
|
11421
11727
|
}
|
|
11422
11728
|
return packs;
|
|
11423
11729
|
}
|
|
11730
|
+
function findStandardStatement(statementIdOrRef) {
|
|
11731
|
+
if (!statementIdOrRef) return null;
|
|
11732
|
+
const [packPrefix, ...rest] = statementIdOrRef.split(":");
|
|
11733
|
+
const targetId = rest.length > 0 ? rest.join(":") : statementIdOrRef;
|
|
11734
|
+
const packs = resolveStandardsPacks(BUNDLED_STANDARDS_PACK_IDS);
|
|
11735
|
+
for (const pack of packs) {
|
|
11736
|
+
if (rest.length > 0 && pack.manifest.id !== packPrefix) continue;
|
|
11737
|
+
const stmt = pack.statements.find((s) => s.id.toLowerCase() === targetId.toLowerCase());
|
|
11738
|
+
if (stmt) {
|
|
11739
|
+
const description = stmt.texts["en"] || Object.values(stmt.texts)[0] || "";
|
|
11740
|
+
const category = stmt.classifications && stmt.classifications.length > 0 ? stmt.classifications.map((c) => c.value).join(", ") : void 0;
|
|
11741
|
+
const gradeBand = Array.isArray(stmt.gradeBand) ? stmt.gradeBand[0] === stmt.gradeBand[1] ? String(stmt.gradeBand[0]) : `${stmt.gradeBand[0]}-${stmt.gradeBand[1]}` : void 0;
|
|
11742
|
+
return {
|
|
11743
|
+
packId: pack.manifest.id,
|
|
11744
|
+
packTitle: pack.manifest.name,
|
|
11745
|
+
statementId: stmt.id,
|
|
11746
|
+
description,
|
|
11747
|
+
category,
|
|
11748
|
+
gradeBand
|
|
11749
|
+
};
|
|
11750
|
+
}
|
|
11751
|
+
}
|
|
11752
|
+
return null;
|
|
11753
|
+
}
|
|
11754
|
+
var STANDARD_REF_REGEX = /\b(?:(?:csta-k12-2017|acm-ieee-cs2023):)?(?:[1-3][A-B]?-[A-Z]{2}-\d{2}|CS2023-[A-Z0-9_-]+)\b/gi;
|
|
11755
|
+
function extractStandardRefs(text) {
|
|
11756
|
+
if (!text) return [];
|
|
11757
|
+
const matches = Array.from(text.matchAll(STANDARD_REF_REGEX)).map((m) => m[0]);
|
|
11758
|
+
return Array.from(new Set(matches));
|
|
11759
|
+
}
|
|
11424
11760
|
|
|
11425
11761
|
// src/services/languageDirective.ts
|
|
11426
11762
|
function resolveTargetLanguageCode(language) {
|
|
@@ -11732,7 +12068,7 @@ type: "LESSON_EDP"
|
|
|
11732
12068
|
- **Estimated Duration:** 90 minutes
|
|
11733
12069
|
- **Project Objective:** [Complete engineering system or functional deliverable students build]
|
|
11734
12070
|
- **Materials & Equipment:** [Detailed hardware, software libraries, and workstation tools]
|
|
11735
|
-
- **Learning Objectives Table:** (LO1, LO2 mapped with EDP Bloom level, Student Evidence, and
|
|
12071
|
+
- **Learning Objectives Table:** (LO1, LO2 mapped with EDP Bloom level, Student Evidence, Success Criteria, and matching Standard ID from [STANDARDS STATEMENTS] if present, e.g. "CSTA: 1B-AP-10" or "CS2023-SDF-01")
|
|
11736
12072
|
|
|
11737
12073
|
### 2. Activity Sequence
|
|
11738
12074
|
> Activity Contract table with columns: Seq, EDP Phase (Ask, Imagine, Plan, Create, Test & Improve, Share & Evaluate), Activity Type, Actor, Purpose, Student Action, Teacher Move, Output/Evidence, LO, Time, Artifact Contract.
|
|
@@ -11782,7 +12118,7 @@ type: "LESSON_GENERAL"
|
|
|
11782
12118
|
- **Estimated Duration:** 90 minutes
|
|
11783
12119
|
- **Materials & Equipment:** [Tools, IDE, workstations, resources]
|
|
11784
12120
|
- **Keywords / Core Concepts:** [Core domain terminology]
|
|
11785
|
-
- **Learning Objectives Table:** (LO1, LO2 with Bloom action verbs, Student Evidence, Success Criteria)
|
|
12121
|
+
- **Learning Objectives Table:** (LO1, LO2 with Bloom action verbs, Student Evidence, Success Criteria, and matching Standard ID from [STANDARDS STATEMENTS] if present, e.g. "CSTA: 1B-AP-10" or "CS2023-SDF-01")
|
|
11786
12122
|
|
|
11787
12123
|
### 2. Activity Sequence
|
|
11788
12124
|
> Activity Contract table with columns: Seq, Lesson Stage (Warm-up, Core Concepts, Guided Practice, Independent Practice, Wrap-up), Activity Type, Actor, Purpose, Student Action, Teacher Move, Output/Evidence, LO, Time, Artifact Contract.
|
|
@@ -11830,7 +12166,7 @@ type: "LESSON_5E"
|
|
|
11830
12166
|
- **Estimated Duration:** 90 minutes
|
|
11831
12167
|
- **Materials & Equipment:** [Tools, IDE, hardware/software specifications]
|
|
11832
12168
|
- **Keywords / Core Concepts:** [Core domain terminology]
|
|
11833
|
-
- **Learning Objectives Table:** (LO1, LO2 with Bloom action verbs, Student Evidence, Success Criteria)
|
|
12169
|
+
- **Learning Objectives Table:** (LO1, LO2 with Bloom action verbs, Student Evidence, Success Criteria, and matching Standard ID from [STANDARDS STATEMENTS] if present, e.g. "CSTA: 1B-AP-10" or "CS2023-SDF-01")
|
|
11834
12170
|
|
|
11835
12171
|
### 2. Activity Sequence
|
|
11836
12172
|
> Activity Contract table with columns: Seq, 5E Phase (Engage, Explore, Explain, Elaborate, Evaluate), Activity Type, Actor, Purpose, Student Action, Teacher Move, Output/Evidence, LO, Time, Artifact Contract.
|
|
@@ -13050,13 +13386,52 @@ ${buildHeadingDirective("EXT", slcMarkdown, targetLang)}`;
|
|
|
13050
13386
|
});
|
|
13051
13387
|
}
|
|
13052
13388
|
}
|
|
13389
|
+
let standardsCoverage;
|
|
13390
|
+
if (packs.length > 0 && lessonContent) {
|
|
13391
|
+
try {
|
|
13392
|
+
const objectives = parseLessonObjectivesWithStandards(lessonContent, concept, bloomLevel, packs);
|
|
13393
|
+
const activities = parseActivitySequenceLo(lessonContent);
|
|
13394
|
+
const quizContent = await storage.readArtifact(projectId, quizRelPath).catch(() => null);
|
|
13395
|
+
const quizQuestions = quizContent ? parseQuizQuestionsLo(quizContent) : [];
|
|
13396
|
+
const selected = selectStatementsForLesson({
|
|
13397
|
+
packs,
|
|
13398
|
+
gradeBand: options.gradeBand ?? [6, 12],
|
|
13399
|
+
topicText: `${lessonTitle} ${concept}`
|
|
13400
|
+
});
|
|
13401
|
+
const targetStatementIds = new Set(selected.map((s) => s.statement.id.toLowerCase()));
|
|
13402
|
+
for (const lo of objectives) {
|
|
13403
|
+
for (const r of lo.standardRefs || []) {
|
|
13404
|
+
targetStatementIds.add(r.replace(/^[^:]+:/, "").toLowerCase());
|
|
13405
|
+
}
|
|
13406
|
+
}
|
|
13407
|
+
const scopedPacks = packs.map((p) => ({
|
|
13408
|
+
...p,
|
|
13409
|
+
statements: p.statements.filter((s) => targetStatementIds.has(s.id.toLowerCase()))
|
|
13410
|
+
})).filter((p) => p.statements.length > 0);
|
|
13411
|
+
if (scopedPacks.length > 0) {
|
|
13412
|
+
standardsCoverage = evaluateStandardsCoverage({
|
|
13413
|
+
packs: scopedPacks,
|
|
13414
|
+
objectives,
|
|
13415
|
+
activities,
|
|
13416
|
+
quizQuestions
|
|
13417
|
+
});
|
|
13418
|
+
onProgress?.(
|
|
13419
|
+
"@reviewer",
|
|
13420
|
+
`\u{1F4CA} Standards Coverage Gate: ${standardsCoverage.verdict} (${standardsCoverage.coveragePct}% coverage, ${standardsCoverage.rows.filter((r) => r.status === "COVERED").length}/${standardsCoverage.rows.length} statements covered)`
|
|
13421
|
+
);
|
|
13422
|
+
}
|
|
13423
|
+
} catch (covErr) {
|
|
13424
|
+
console.warn("[lessonProductionService] Failed to evaluate standards coverage:", covErr?.message || covErr);
|
|
13425
|
+
}
|
|
13426
|
+
}
|
|
13053
13427
|
return {
|
|
13054
13428
|
lessonId: lessonCode,
|
|
13055
13429
|
pedagogy,
|
|
13056
13430
|
producedArtifacts,
|
|
13057
13431
|
pausedForReview: false,
|
|
13058
13432
|
contextInjection: lessonInjection && lessonInjection.verified ? expositionInjection || lessonInjection : lessonInjection || expositionInjection,
|
|
13059
|
-
promptChars: commonContext.length
|
|
13433
|
+
promptChars: commonContext.length,
|
|
13434
|
+
standardsCoverage
|
|
13060
13435
|
};
|
|
13061
13436
|
}
|
|
13062
13437
|
function parseLessonObjectives(lessonContent, concept, bloomLevel) {
|
|
@@ -13078,6 +13453,65 @@ function parseLessonObjectives(lessonContent, concept, bloomLevel) {
|
|
|
13078
13453
|
}
|
|
13079
13454
|
return objectives.slice(0, 6);
|
|
13080
13455
|
}
|
|
13456
|
+
function parseLessonObjectivesWithStandards(lessonContent, concept, bloomLevel, _packs) {
|
|
13457
|
+
const baseObjectives = parseLessonObjectives(lessonContent, concept, bloomLevel);
|
|
13458
|
+
const lines = lessonContent.split("\n");
|
|
13459
|
+
return baseObjectives.map((lo) => {
|
|
13460
|
+
const refs = /* @__PURE__ */ new Set();
|
|
13461
|
+
for (const line of lines) {
|
|
13462
|
+
if (line.includes(lo.code)) {
|
|
13463
|
+
const found = extractStandardRefs(line);
|
|
13464
|
+
for (const r of found) refs.add(r);
|
|
13465
|
+
}
|
|
13466
|
+
}
|
|
13467
|
+
return {
|
|
13468
|
+
...lo,
|
|
13469
|
+
standardRefs: refs.size > 0 ? Array.from(refs) : void 0
|
|
13470
|
+
};
|
|
13471
|
+
});
|
|
13472
|
+
}
|
|
13473
|
+
function parseActivitySequenceLo(lessonContent) {
|
|
13474
|
+
const activities = [];
|
|
13475
|
+
const lines = lessonContent.split("\n");
|
|
13476
|
+
let currentSeq = 1;
|
|
13477
|
+
for (const line of lines) {
|
|
13478
|
+
const matchActivity = line.match(/(?:Hoạt động|Activity|Phase|Giai đoạn)\s*(\d+)/i);
|
|
13479
|
+
const loMatches = Array.from(line.matchAll(/\b(LO\d+)\b/gi)).map((m) => m[1].toUpperCase());
|
|
13480
|
+
if (matchActivity && loMatches.length > 0) {
|
|
13481
|
+
activities.push({
|
|
13482
|
+
seq: parseInt(matchActivity[1], 10),
|
|
13483
|
+
lo: Array.from(new Set(loMatches))
|
|
13484
|
+
});
|
|
13485
|
+
} else if (loMatches.length > 0 && line.trim().startsWith("|")) {
|
|
13486
|
+
activities.push({
|
|
13487
|
+
seq: currentSeq++,
|
|
13488
|
+
lo: Array.from(new Set(loMatches))
|
|
13489
|
+
});
|
|
13490
|
+
}
|
|
13491
|
+
}
|
|
13492
|
+
if (activities.length === 0) {
|
|
13493
|
+
const allLos = Array.from(lessonContent.matchAll(/\b(LO\d+)\b/gi)).map((m) => m[1].toUpperCase());
|
|
13494
|
+
if (allLos.length > 0) {
|
|
13495
|
+
activities.push({ seq: 1, lo: Array.from(new Set(allLos)) });
|
|
13496
|
+
}
|
|
13497
|
+
}
|
|
13498
|
+
return activities;
|
|
13499
|
+
}
|
|
13500
|
+
function parseQuizQuestionsLo(quizContent) {
|
|
13501
|
+
const questions = [];
|
|
13502
|
+
const lines = quizContent.split("\n");
|
|
13503
|
+
for (const line of lines) {
|
|
13504
|
+
const loMatch = line.match(/\b(LO\d+)\b/i);
|
|
13505
|
+
const aoMatch = line.match(/\b(AO\d+)\b/i);
|
|
13506
|
+
if (loMatch || aoMatch) {
|
|
13507
|
+
questions.push({
|
|
13508
|
+
alignedLO: loMatch ? loMatch[1].toUpperCase() : void 0,
|
|
13509
|
+
alignedAO: aoMatch ? aoMatch[1].toUpperCase() : void 0
|
|
13510
|
+
});
|
|
13511
|
+
}
|
|
13512
|
+
}
|
|
13513
|
+
return questions;
|
|
13514
|
+
}
|
|
13081
13515
|
async function judgeSatelliteArtifact(ctx) {
|
|
13082
13516
|
const { storage, projectId, lessonCode, sat, content } = ctx;
|
|
13083
13517
|
try {
|
|
@@ -16802,120 +17236,6 @@ var MisconceptionEvaluator = class {
|
|
|
16802
17236
|
};
|
|
16803
17237
|
}
|
|
16804
17238
|
};
|
|
16805
|
-
|
|
16806
|
-
// src/standards/standardsCoverageGate.ts
|
|
16807
|
-
function resolveStatementRef(ref, packs) {
|
|
16808
|
-
const [head, ...rest] = ref.split(":");
|
|
16809
|
-
const candidatePacks = rest.length > 0 ? packs.filter((p) => p.manifest.id === head) : packs;
|
|
16810
|
-
const statementId = rest.length > 0 ? rest.join(":") : ref;
|
|
16811
|
-
for (const p of candidatePacks) {
|
|
16812
|
-
if (p.statements.some((s) => s.id === statementId)) return { pack: p, statementId };
|
|
16813
|
-
}
|
|
16814
|
-
return null;
|
|
16815
|
-
}
|
|
16816
|
-
function evaluateStandardsCoverage(input) {
|
|
16817
|
-
const rows = [];
|
|
16818
|
-
const aoToLo = /* @__PURE__ */ new Map();
|
|
16819
|
-
for (const ao of input.assessmentObjectives ?? []) aoToLo.set(ao.aoCode, ao.alignedLO);
|
|
16820
|
-
const loToRefs = /* @__PURE__ */ new Map();
|
|
16821
|
-
for (const lo of input.objectives) {
|
|
16822
|
-
loToRefs.set(lo.code, new Set(lo.standardRefs ?? []));
|
|
16823
|
-
}
|
|
16824
|
-
const taughtLOs = /* @__PURE__ */ new Set();
|
|
16825
|
-
for (const act of input.activities ?? []) for (const lo of act.lo) taughtLOs.add(lo);
|
|
16826
|
-
const assessedLOs = /* @__PURE__ */ new Set();
|
|
16827
|
-
for (const q of input.quizQuestions) {
|
|
16828
|
-
if (q.alignedLO) assessedLOs.add(q.alignedLO);
|
|
16829
|
-
if (q.alignedAO) {
|
|
16830
|
-
const lo = aoToLo.get(q.alignedAO);
|
|
16831
|
-
if (lo) assessedLOs.add(lo);
|
|
16832
|
-
}
|
|
16833
|
-
}
|
|
16834
|
-
for (const pack of input.packs) {
|
|
16835
|
-
const mappingByStatement = /* @__PURE__ */ new Map();
|
|
16836
|
-
for (const m of pack.mappings ?? []) {
|
|
16837
|
-
const prev = mappingByStatement.get(m.statementId);
|
|
16838
|
-
if (!prev || prev !== "covers" && m.kind === "covers" || prev === "extends" && m.kind !== "extends") {
|
|
16839
|
-
mappingByStatement.set(m.statementId, m.kind);
|
|
16840
|
-
}
|
|
16841
|
-
}
|
|
16842
|
-
for (const statement of pack.statements) {
|
|
16843
|
-
const refFull = `${pack.manifest.id}:${statement.id}`;
|
|
16844
|
-
const issues = [];
|
|
16845
|
-
const los = input.objectives.filter((lo) => (lo.standardRefs ?? []).some((r) => r === statement.id || r === refFull)).map((lo) => lo.code);
|
|
16846
|
-
const kind = mappingByStatement.get(statement.id);
|
|
16847
|
-
const hasMapping = kind !== void 0;
|
|
16848
|
-
const isComplianceRelevant = kind === "covers";
|
|
16849
|
-
const hasActivity = los.some((lo) => taughtLOs.has(lo));
|
|
16850
|
-
const hasAssessment = los.some((lo) => assessedLOs.has(lo));
|
|
16851
|
-
let status;
|
|
16852
|
-
if (!hasMapping) status = "UNMAPPED";
|
|
16853
|
-
else if (!isComplianceRelevant) status = "PARTIAL";
|
|
16854
|
-
else if (los.length > 0 && hasActivity && hasAssessment) status = "COVERED";
|
|
16855
|
-
else status = "UNCOVERED";
|
|
16856
|
-
if (status === "UNCOVERED") {
|
|
16857
|
-
if (los.length === 0) issues.push("No learning objective anchors this statement (missing standardRefs).");
|
|
16858
|
-
else {
|
|
16859
|
-
if (!hasActivity) issues.push(`Anchored LO(s) ${los.join(", ")} have no activity in lesson flow.`);
|
|
16860
|
-
if (!hasAssessment) issues.push(`Anchored LO(s) ${los.join(", ")} are not measured by any quiz question.`);
|
|
16861
|
-
}
|
|
16862
|
-
}
|
|
16863
|
-
rows.push({
|
|
16864
|
-
packId: pack.manifest.id,
|
|
16865
|
-
statementId: statement.id,
|
|
16866
|
-
statementText: Object.values(statement.texts)[0] ?? "",
|
|
16867
|
-
status,
|
|
16868
|
-
objectives: los,
|
|
16869
|
-
hasActivity,
|
|
16870
|
-
hasAssessment,
|
|
16871
|
-
issues
|
|
16872
|
-
});
|
|
16873
|
-
}
|
|
16874
|
-
}
|
|
16875
|
-
for (const lo of input.objectives) {
|
|
16876
|
-
for (const r of lo.standardRefs ?? []) {
|
|
16877
|
-
if (!resolveStatementRef(r, input.packs)) {
|
|
16878
|
-
rows.push({
|
|
16879
|
-
packId: "(unresolved)",
|
|
16880
|
-
statementId: r,
|
|
16881
|
-
statementText: "",
|
|
16882
|
-
status: "UNCOVERED",
|
|
16883
|
-
objectives: [lo.code],
|
|
16884
|
-
hasActivity: false,
|
|
16885
|
-
hasAssessment: false,
|
|
16886
|
-
issues: [`standardRef "${r}" does not exist in any adopted pack \u2014 likely a hallucinated or stale ID`]
|
|
16887
|
-
});
|
|
16888
|
-
}
|
|
16889
|
-
}
|
|
16890
|
-
}
|
|
16891
|
-
const complianceRows = rows.filter((r) => r.status !== "UNMAPPED" && r.status !== "PARTIAL");
|
|
16892
|
-
const covered = complianceRows.filter((r) => r.status === "COVERED").length;
|
|
16893
|
-
const coveragePct = complianceRows.length === 0 ? 100 : Math.round(covered / complianceRows.length * 100);
|
|
16894
|
-
const unresolvedCount = rows.filter((r) => r.packId === "(unresolved)").length;
|
|
16895
|
-
const verdict = unresolvedCount > 0 || coveragePct < 60 ? "FAIL" : coveragePct < 100 ? "WARN" : "PASS";
|
|
16896
|
-
const lines = [
|
|
16897
|
-
"# Standards Coverage Report",
|
|
16898
|
-
"",
|
|
16899
|
-
`- Verdict: **${verdict}**`,
|
|
16900
|
-
`- Compliance coverage: **${coveragePct}%** (${covered}/${complianceRows.length} "covers" statements fully taught + assessed)`,
|
|
16901
|
-
`- Unresolved standardRefs: ${unresolvedCount}`,
|
|
16902
|
-
"",
|
|
16903
|
-
"| Pack | Statement | Status | LOs | Activity | Assessment |",
|
|
16904
|
-
"|---|---|---|---|---|---|",
|
|
16905
|
-
...rows.map(
|
|
16906
|
-
(r) => `|${r.packId}|${r.statementId}|${r.status}|${r.objectives.join(", ") || "\u2014"}|${r.hasActivity ? "\u2713" : "\u2717"}|${r.hasAssessment ? "\u2713" : "\u2717"}|`
|
|
16907
|
-
)
|
|
16908
|
-
];
|
|
16909
|
-
const issueLines = rows.filter((r) => r.issues.length > 0).flatMap((r) => r.issues.map((i) => `- [${r.packId}:${r.statementId}] ${i}`));
|
|
16910
|
-
if (issueLines.length > 0) lines.push("", "## Issues", ...issueLines);
|
|
16911
|
-
return {
|
|
16912
|
-
verdict,
|
|
16913
|
-
coveragePct,
|
|
16914
|
-
rows,
|
|
16915
|
-
summary: `Standards coverage ${coveragePct}% \u2014 verdict ${verdict}`,
|
|
16916
|
-
rawMarkdownReport: lines.join("\n")
|
|
16917
|
-
};
|
|
16918
|
-
}
|
|
16919
17239
|
var StandardsRegistryAdapter = class {
|
|
16920
17240
|
client;
|
|
16921
17241
|
constructor(config = {}) {
|
|
@@ -17728,6 +18048,7 @@ exports.SELF_LAB_TEMPLATE = SELF_LAB_TEMPLATE;
|
|
|
17728
18048
|
exports.SLIDE_CANONICAL_METHODOLOGY = SLIDE_CANONICAL_METHODOLOGY;
|
|
17729
18049
|
exports.SLIDE_LAYOUT_PRESETS = SLIDE_LAYOUT_PRESETS;
|
|
17730
18050
|
exports.SLIDE_TEMPLATE = SLIDE_TEMPLATE;
|
|
18051
|
+
exports.STANDARD_REF_REGEX = STANDARD_REF_REGEX;
|
|
17731
18052
|
exports.STANDARD_SOT_FILES = STANDARD_SOT_FILES;
|
|
17732
18053
|
exports.STATION_ROTATION_TEMPLATE = STATION_ROTATION_TEMPLATE;
|
|
17733
18054
|
exports.ScaffoldDecisionEntrySchema = ScaffoldDecisionEntrySchema;
|
|
@@ -17826,8 +18147,10 @@ exports.expositionCacheKey = expositionCacheKey;
|
|
|
17826
18147
|
exports.extractScopeSequenceRows = extractScopeSequenceRows;
|
|
17827
18148
|
exports.extractSectionHeadingsFromSLC = extractSectionHeadingsFromSLC;
|
|
17828
18149
|
exports.extractSessionSlice = extractSessionSlice;
|
|
18150
|
+
exports.extractStandardRefs = extractStandardRefs;
|
|
17829
18151
|
exports.extractStreamChunk = extractStreamChunk;
|
|
17830
18152
|
exports.extractThoughtAndContent = extractThoughtAndContent;
|
|
18153
|
+
exports.findStandardStatement = findStandardStatement;
|
|
17831
18154
|
exports.formatQuizzesToCsv = formatQuizzesToCsv;
|
|
17832
18155
|
exports.fulfillMediaLedger = fulfillMediaLedger;
|
|
17833
18156
|
exports.gateModeFor = gateModeFor;
|