@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.
- 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 +471 -139
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.mjs +469 -140
- 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 +222 -21
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.mjs +222 -21
- 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,9 +9841,11 @@ 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
|
-
const
|
|
9845
|
-
const
|
|
9846
|
+
const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
|
|
9847
|
+
const sections = parseMarkdownSections(source, slcMap, effectiveArtifactType);
|
|
9848
|
+
const metaBlock = buildMetaBlock(source, effectiveArtifactType);
|
|
9846
9849
|
if (sections.length === 0) {
|
|
9847
9850
|
issues.push("parse:no-sections");
|
|
9848
9851
|
const excerpt2 = truncateByBudget(source, budget);
|
|
@@ -9858,44 +9861,74 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
9858
9861
|
};
|
|
9859
9862
|
}
|
|
9860
9863
|
const byCanonical = /* @__PURE__ */ new Map();
|
|
9864
|
+
const byCleanTitle = /* @__PURE__ */ new Map();
|
|
9861
9865
|
const unmatched = [];
|
|
9862
9866
|
for (const s of sections) {
|
|
9863
9867
|
if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
|
|
9864
9868
|
byCanonical.set(s.canonicalKey, s);
|
|
9865
|
-
}
|
|
9869
|
+
}
|
|
9870
|
+
const norm = normalizeHeading(s.cleanTitle);
|
|
9871
|
+
if (!byCleanTitle.has(norm)) {
|
|
9872
|
+
byCleanTitle.set(norm, s);
|
|
9873
|
+
}
|
|
9874
|
+
if (!s.canonicalKey) {
|
|
9866
9875
|
unmatched.push(s);
|
|
9867
9876
|
}
|
|
9868
9877
|
}
|
|
9869
9878
|
const priorities = opts.priorities ?? DEFAULT_LESSON_PRIORITIES;
|
|
9870
9879
|
const includedSections = [];
|
|
9871
9880
|
const blocks = [];
|
|
9872
|
-
|
|
9881
|
+
const initialOverhead = metaBlock ? metaBlock.length + 2 : 0;
|
|
9882
|
+
let used = initialOverhead;
|
|
9873
9883
|
const tryAdd = (heading, body, key) => {
|
|
9874
9884
|
const trimmedBody = body.trim();
|
|
9875
9885
|
if (!trimmedBody) return false;
|
|
9876
9886
|
const block = `## ${heading}
|
|
9877
9887
|
|
|
9878
9888
|
${trimmedBody}`;
|
|
9879
|
-
if (used + block.length
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
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;
|
|
9884
9916
|
};
|
|
9885
9917
|
blocks.push(metaBlock);
|
|
9886
9918
|
let sectionAware = false;
|
|
9887
9919
|
for (const key of priorities) {
|
|
9888
|
-
const sec = byCanonical.get(key);
|
|
9920
|
+
const sec = byCanonical.get(key) || byCleanTitle.get(normalizeHeading(key));
|
|
9889
9921
|
if (!sec) continue;
|
|
9890
9922
|
sectionAware = true;
|
|
9891
9923
|
if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
|
|
9892
9924
|
}
|
|
9893
9925
|
for (const [key, sec] of byCanonical) {
|
|
9894
|
-
if (includedSections.includes(key)) continue;
|
|
9926
|
+
if (includedSections.includes(key) || includedSections.includes(sec.cleanTitle)) continue;
|
|
9895
9927
|
if (used >= budget) break;
|
|
9896
9928
|
if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
|
|
9897
9929
|
}
|
|
9898
9930
|
for (const sec of unmatched) {
|
|
9931
|
+
if (includedSections.includes(sec.cleanTitle)) continue;
|
|
9899
9932
|
if (used >= budget) break;
|
|
9900
9933
|
if (!tryAdd(sec.cleanTitle, sec.body, sec.cleanTitle)) break;
|
|
9901
9934
|
}
|
|
@@ -9903,17 +9936,16 @@ ${trimmedBody}`;
|
|
|
9903
9936
|
issues.push("parse:no-canonical-resolution");
|
|
9904
9937
|
}
|
|
9905
9938
|
if (priorities.length > 0 && !priorities.some((k) => includedSections.includes(k))) {
|
|
9906
|
-
issues.push("parse:no-priority-resolution");
|
|
9939
|
+
issues.push(sections.length === 0 ? "parse:no-sections" : "parse:no-priority-resolution");
|
|
9907
9940
|
}
|
|
9908
9941
|
let excerpt = blocks.join("\n\n");
|
|
9909
9942
|
if (excerpt.length > budget) {
|
|
9910
9943
|
excerpt = truncateByBudget(excerpt, budget);
|
|
9911
9944
|
}
|
|
9912
|
-
|
|
9913
|
-
if (excerpt.length - metaBlock.length < effectiveMinChars) {
|
|
9945
|
+
if (excerpt.length - metaBlock.length < minContentChars) {
|
|
9914
9946
|
issues.push("content:insufficient");
|
|
9915
9947
|
}
|
|
9916
|
-
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;
|
|
9917
9949
|
return {
|
|
9918
9950
|
excerpt,
|
|
9919
9951
|
verified,
|
|
@@ -9973,7 +10005,7 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
|
9973
10005
|
}
|
|
9974
10006
|
}
|
|
9975
10007
|
const flush = () => {
|
|
9976
|
-
if (!currentHeading
|
|
10008
|
+
if (!currentHeading) return;
|
|
9977
10009
|
const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
|
|
9978
10010
|
const norm = normalizeHeading(cleanTitle);
|
|
9979
10011
|
const canonicalKey = reverseMap.get(norm) || findCanonicalFuzzy(norm);
|
|
@@ -10033,7 +10065,7 @@ function truncateByBudget(source, budget) {
|
|
|
10033
10065
|
if (fenceCount % 2 === 1) cut += "\n```";
|
|
10034
10066
|
return cut;
|
|
10035
10067
|
}
|
|
10036
|
-
function buildMetaBlock(source) {
|
|
10068
|
+
function buildMetaBlock(source, artifactType) {
|
|
10037
10069
|
const fm = source.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
|
|
10038
10070
|
const pick = (key) => {
|
|
10039
10071
|
if (!fm) return "";
|
|
@@ -10042,9 +10074,17 @@ function buildMetaBlock(source) {
|
|
|
10042
10074
|
};
|
|
10043
10075
|
const id = pick("id");
|
|
10044
10076
|
const title = pick("title");
|
|
10045
|
-
const type = pick("type");
|
|
10077
|
+
const type = pick("type") || artifactType || "";
|
|
10046
10078
|
return `<!-- SOURCE: ${type || "ARTIFACT"} | ${id || "unknown"}${title ? ` \u2014 ${title}` : ""} (section-aware excerpt; canonical knowledge, do not contradict) -->`;
|
|
10047
10079
|
}
|
|
10080
|
+
function deriveArtifactTypeFromFileName(fileName) {
|
|
10081
|
+
if (!fileName) return void 0;
|
|
10082
|
+
const base = fileName.replace(/\.md$/i, "");
|
|
10083
|
+
const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|SECTION_LANGUAGE_CONTRACT|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
|
|
10084
|
+
if (multiWord) return multiWord[1].toUpperCase();
|
|
10085
|
+
const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
|
|
10086
|
+
return token ? token[1] : void 0;
|
|
10087
|
+
}
|
|
10048
10088
|
|
|
10049
10089
|
// src/services/knowledgeExpositionService.ts
|
|
10050
10090
|
var EXPOSITION_REL = (lessonCode) => "_sot/expositions/" + lessonCode + ".md";
|
|
@@ -10948,6 +10988,120 @@ function buildStandardsContext(input) {
|
|
|
10948
10988
|
const selected = selectStatementsForLesson(input);
|
|
10949
10989
|
return { block: buildStandardsContextBlock(selected, { language: input.language }), selected };
|
|
10950
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
|
+
}
|
|
10951
11105
|
var BloomHintSchema = zod.z.object({
|
|
10952
11106
|
process: zod.z.enum(["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"]).describe("Cognitive process axis"),
|
|
10953
11107
|
knowledge: zod.z.enum(["FACTUAL", "CONCEPTUAL", "PROCEDURAL", "METACOGNITIVE"]).optional().describe("Knowledge dimension axis (optional \u2014 most source standards do not tag it)")
|
|
@@ -11383,9 +11537,170 @@ var csta_k12_2017_default = {
|
|
|
11383
11537
|
]
|
|
11384
11538
|
};
|
|
11385
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
|
+
|
|
11386
11700
|
// src/standards/bundledPacks.ts
|
|
11387
11701
|
var BUNDLED_PACK_RECORDS = {
|
|
11388
|
-
"csta-k12-2017": csta_k12_2017_default
|
|
11702
|
+
"csta-k12-2017": csta_k12_2017_default,
|
|
11703
|
+
"acm-ieee-cs2023": acm_ieee_cs2023_default
|
|
11389
11704
|
};
|
|
11390
11705
|
var BUNDLED_STANDARDS_PACK_IDS = Object.keys(BUNDLED_PACK_RECORDS).sort();
|
|
11391
11706
|
var parsedPackCache = /* @__PURE__ */ new Map();
|
|
@@ -11412,6 +11727,36 @@ function resolveStandardsPacks(packIds) {
|
|
|
11412
11727
|
}
|
|
11413
11728
|
return packs;
|
|
11414
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
|
+
}
|
|
11415
11760
|
|
|
11416
11761
|
// src/services/languageDirective.ts
|
|
11417
11762
|
function resolveTargetLanguageCode(language) {
|
|
@@ -11723,7 +12068,7 @@ type: "LESSON_EDP"
|
|
|
11723
12068
|
- **Estimated Duration:** 90 minutes
|
|
11724
12069
|
- **Project Objective:** [Complete engineering system or functional deliverable students build]
|
|
11725
12070
|
- **Materials & Equipment:** [Detailed hardware, software libraries, and workstation tools]
|
|
11726
|
-
- **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")
|
|
11727
12072
|
|
|
11728
12073
|
### 2. Activity Sequence
|
|
11729
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.
|
|
@@ -11773,7 +12118,7 @@ type: "LESSON_GENERAL"
|
|
|
11773
12118
|
- **Estimated Duration:** 90 minutes
|
|
11774
12119
|
- **Materials & Equipment:** [Tools, IDE, workstations, resources]
|
|
11775
12120
|
- **Keywords / Core Concepts:** [Core domain terminology]
|
|
11776
|
-
- **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")
|
|
11777
12122
|
|
|
11778
12123
|
### 2. Activity Sequence
|
|
11779
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.
|
|
@@ -11821,7 +12166,7 @@ type: "LESSON_5E"
|
|
|
11821
12166
|
- **Estimated Duration:** 90 minutes
|
|
11822
12167
|
- **Materials & Equipment:** [Tools, IDE, hardware/software specifications]
|
|
11823
12168
|
- **Keywords / Core Concepts:** [Core domain terminology]
|
|
11824
|
-
- **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")
|
|
11825
12170
|
|
|
11826
12171
|
### 2. Activity Sequence
|
|
11827
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.
|
|
@@ -13041,13 +13386,52 @@ ${buildHeadingDirective("EXT", slcMarkdown, targetLang)}`;
|
|
|
13041
13386
|
});
|
|
13042
13387
|
}
|
|
13043
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
|
+
}
|
|
13044
13427
|
return {
|
|
13045
13428
|
lessonId: lessonCode,
|
|
13046
13429
|
pedagogy,
|
|
13047
13430
|
producedArtifacts,
|
|
13048
13431
|
pausedForReview: false,
|
|
13049
13432
|
contextInjection: lessonInjection && lessonInjection.verified ? expositionInjection || lessonInjection : lessonInjection || expositionInjection,
|
|
13050
|
-
promptChars: commonContext.length
|
|
13433
|
+
promptChars: commonContext.length,
|
|
13434
|
+
standardsCoverage
|
|
13051
13435
|
};
|
|
13052
13436
|
}
|
|
13053
13437
|
function parseLessonObjectives(lessonContent, concept, bloomLevel) {
|
|
@@ -13069,6 +13453,65 @@ function parseLessonObjectives(lessonContent, concept, bloomLevel) {
|
|
|
13069
13453
|
}
|
|
13070
13454
|
return objectives.slice(0, 6);
|
|
13071
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
|
+
}
|
|
13072
13515
|
async function judgeSatelliteArtifact(ctx) {
|
|
13073
13516
|
const { storage, projectId, lessonCode, sat, content } = ctx;
|
|
13074
13517
|
try {
|
|
@@ -16793,120 +17236,6 @@ var MisconceptionEvaluator = class {
|
|
|
16793
17236
|
};
|
|
16794
17237
|
}
|
|
16795
17238
|
};
|
|
16796
|
-
|
|
16797
|
-
// src/standards/standardsCoverageGate.ts
|
|
16798
|
-
function resolveStatementRef(ref, packs) {
|
|
16799
|
-
const [head, ...rest] = ref.split(":");
|
|
16800
|
-
const candidatePacks = rest.length > 0 ? packs.filter((p) => p.manifest.id === head) : packs;
|
|
16801
|
-
const statementId = rest.length > 0 ? rest.join(":") : ref;
|
|
16802
|
-
for (const p of candidatePacks) {
|
|
16803
|
-
if (p.statements.some((s) => s.id === statementId)) return { pack: p, statementId };
|
|
16804
|
-
}
|
|
16805
|
-
return null;
|
|
16806
|
-
}
|
|
16807
|
-
function evaluateStandardsCoverage(input) {
|
|
16808
|
-
const rows = [];
|
|
16809
|
-
const aoToLo = /* @__PURE__ */ new Map();
|
|
16810
|
-
for (const ao of input.assessmentObjectives ?? []) aoToLo.set(ao.aoCode, ao.alignedLO);
|
|
16811
|
-
const loToRefs = /* @__PURE__ */ new Map();
|
|
16812
|
-
for (const lo of input.objectives) {
|
|
16813
|
-
loToRefs.set(lo.code, new Set(lo.standardRefs ?? []));
|
|
16814
|
-
}
|
|
16815
|
-
const taughtLOs = /* @__PURE__ */ new Set();
|
|
16816
|
-
for (const act of input.activities ?? []) for (const lo of act.lo) taughtLOs.add(lo);
|
|
16817
|
-
const assessedLOs = /* @__PURE__ */ new Set();
|
|
16818
|
-
for (const q of input.quizQuestions) {
|
|
16819
|
-
if (q.alignedLO) assessedLOs.add(q.alignedLO);
|
|
16820
|
-
if (q.alignedAO) {
|
|
16821
|
-
const lo = aoToLo.get(q.alignedAO);
|
|
16822
|
-
if (lo) assessedLOs.add(lo);
|
|
16823
|
-
}
|
|
16824
|
-
}
|
|
16825
|
-
for (const pack of input.packs) {
|
|
16826
|
-
const mappingByStatement = /* @__PURE__ */ new Map();
|
|
16827
|
-
for (const m of pack.mappings ?? []) {
|
|
16828
|
-
const prev = mappingByStatement.get(m.statementId);
|
|
16829
|
-
if (!prev || prev !== "covers" && m.kind === "covers" || prev === "extends" && m.kind !== "extends") {
|
|
16830
|
-
mappingByStatement.set(m.statementId, m.kind);
|
|
16831
|
-
}
|
|
16832
|
-
}
|
|
16833
|
-
for (const statement of pack.statements) {
|
|
16834
|
-
const refFull = `${pack.manifest.id}:${statement.id}`;
|
|
16835
|
-
const issues = [];
|
|
16836
|
-
const los = input.objectives.filter((lo) => (lo.standardRefs ?? []).some((r) => r === statement.id || r === refFull)).map((lo) => lo.code);
|
|
16837
|
-
const kind = mappingByStatement.get(statement.id);
|
|
16838
|
-
const hasMapping = kind !== void 0;
|
|
16839
|
-
const isComplianceRelevant = kind === "covers";
|
|
16840
|
-
const hasActivity = los.some((lo) => taughtLOs.has(lo));
|
|
16841
|
-
const hasAssessment = los.some((lo) => assessedLOs.has(lo));
|
|
16842
|
-
let status;
|
|
16843
|
-
if (!hasMapping) status = "UNMAPPED";
|
|
16844
|
-
else if (!isComplianceRelevant) status = "PARTIAL";
|
|
16845
|
-
else if (los.length > 0 && hasActivity && hasAssessment) status = "COVERED";
|
|
16846
|
-
else status = "UNCOVERED";
|
|
16847
|
-
if (status === "UNCOVERED") {
|
|
16848
|
-
if (los.length === 0) issues.push("No learning objective anchors this statement (missing standardRefs).");
|
|
16849
|
-
else {
|
|
16850
|
-
if (!hasActivity) issues.push(`Anchored LO(s) ${los.join(", ")} have no activity in lesson flow.`);
|
|
16851
|
-
if (!hasAssessment) issues.push(`Anchored LO(s) ${los.join(", ")} are not measured by any quiz question.`);
|
|
16852
|
-
}
|
|
16853
|
-
}
|
|
16854
|
-
rows.push({
|
|
16855
|
-
packId: pack.manifest.id,
|
|
16856
|
-
statementId: statement.id,
|
|
16857
|
-
statementText: Object.values(statement.texts)[0] ?? "",
|
|
16858
|
-
status,
|
|
16859
|
-
objectives: los,
|
|
16860
|
-
hasActivity,
|
|
16861
|
-
hasAssessment,
|
|
16862
|
-
issues
|
|
16863
|
-
});
|
|
16864
|
-
}
|
|
16865
|
-
}
|
|
16866
|
-
for (const lo of input.objectives) {
|
|
16867
|
-
for (const r of lo.standardRefs ?? []) {
|
|
16868
|
-
if (!resolveStatementRef(r, input.packs)) {
|
|
16869
|
-
rows.push({
|
|
16870
|
-
packId: "(unresolved)",
|
|
16871
|
-
statementId: r,
|
|
16872
|
-
statementText: "",
|
|
16873
|
-
status: "UNCOVERED",
|
|
16874
|
-
objectives: [lo.code],
|
|
16875
|
-
hasActivity: false,
|
|
16876
|
-
hasAssessment: false,
|
|
16877
|
-
issues: [`standardRef "${r}" does not exist in any adopted pack \u2014 likely a hallucinated or stale ID`]
|
|
16878
|
-
});
|
|
16879
|
-
}
|
|
16880
|
-
}
|
|
16881
|
-
}
|
|
16882
|
-
const complianceRows = rows.filter((r) => r.status !== "UNMAPPED" && r.status !== "PARTIAL");
|
|
16883
|
-
const covered = complianceRows.filter((r) => r.status === "COVERED").length;
|
|
16884
|
-
const coveragePct = complianceRows.length === 0 ? 100 : Math.round(covered / complianceRows.length * 100);
|
|
16885
|
-
const unresolvedCount = rows.filter((r) => r.packId === "(unresolved)").length;
|
|
16886
|
-
const verdict = unresolvedCount > 0 || coveragePct < 60 ? "FAIL" : coveragePct < 100 ? "WARN" : "PASS";
|
|
16887
|
-
const lines = [
|
|
16888
|
-
"# Standards Coverage Report",
|
|
16889
|
-
"",
|
|
16890
|
-
`- Verdict: **${verdict}**`,
|
|
16891
|
-
`- Compliance coverage: **${coveragePct}%** (${covered}/${complianceRows.length} "covers" statements fully taught + assessed)`,
|
|
16892
|
-
`- Unresolved standardRefs: ${unresolvedCount}`,
|
|
16893
|
-
"",
|
|
16894
|
-
"| Pack | Statement | Status | LOs | Activity | Assessment |",
|
|
16895
|
-
"|---|---|---|---|---|---|",
|
|
16896
|
-
...rows.map(
|
|
16897
|
-
(r) => `|${r.packId}|${r.statementId}|${r.status}|${r.objectives.join(", ") || "\u2014"}|${r.hasActivity ? "\u2713" : "\u2717"}|${r.hasAssessment ? "\u2713" : "\u2717"}|`
|
|
16898
|
-
)
|
|
16899
|
-
];
|
|
16900
|
-
const issueLines = rows.filter((r) => r.issues.length > 0).flatMap((r) => r.issues.map((i) => `- [${r.packId}:${r.statementId}] ${i}`));
|
|
16901
|
-
if (issueLines.length > 0) lines.push("", "## Issues", ...issueLines);
|
|
16902
|
-
return {
|
|
16903
|
-
verdict,
|
|
16904
|
-
coveragePct,
|
|
16905
|
-
rows,
|
|
16906
|
-
summary: `Standards coverage ${coveragePct}% \u2014 verdict ${verdict}`,
|
|
16907
|
-
rawMarkdownReport: lines.join("\n")
|
|
16908
|
-
};
|
|
16909
|
-
}
|
|
16910
17239
|
var StandardsRegistryAdapter = class {
|
|
16911
17240
|
client;
|
|
16912
17241
|
constructor(config = {}) {
|
|
@@ -17719,6 +18048,7 @@ exports.SELF_LAB_TEMPLATE = SELF_LAB_TEMPLATE;
|
|
|
17719
18048
|
exports.SLIDE_CANONICAL_METHODOLOGY = SLIDE_CANONICAL_METHODOLOGY;
|
|
17720
18049
|
exports.SLIDE_LAYOUT_PRESETS = SLIDE_LAYOUT_PRESETS;
|
|
17721
18050
|
exports.SLIDE_TEMPLATE = SLIDE_TEMPLATE;
|
|
18051
|
+
exports.STANDARD_REF_REGEX = STANDARD_REF_REGEX;
|
|
17722
18052
|
exports.STANDARD_SOT_FILES = STANDARD_SOT_FILES;
|
|
17723
18053
|
exports.STATION_ROTATION_TEMPLATE = STATION_ROTATION_TEMPLATE;
|
|
17724
18054
|
exports.ScaffoldDecisionEntrySchema = ScaffoldDecisionEntrySchema;
|
|
@@ -17817,8 +18147,10 @@ exports.expositionCacheKey = expositionCacheKey;
|
|
|
17817
18147
|
exports.extractScopeSequenceRows = extractScopeSequenceRows;
|
|
17818
18148
|
exports.extractSectionHeadingsFromSLC = extractSectionHeadingsFromSLC;
|
|
17819
18149
|
exports.extractSessionSlice = extractSessionSlice;
|
|
18150
|
+
exports.extractStandardRefs = extractStandardRefs;
|
|
17820
18151
|
exports.extractStreamChunk = extractStreamChunk;
|
|
17821
18152
|
exports.extractThoughtAndContent = extractThoughtAndContent;
|
|
18153
|
+
exports.findStandardStatement = findStandardStatement;
|
|
17822
18154
|
exports.formatQuizzesToCsv = formatQuizzesToCsv;
|
|
17823
18155
|
exports.fulfillMediaLedger = fulfillMediaLedger;
|
|
17824
18156
|
exports.gateModeFor = gateModeFor;
|