@thanh01.pmt/curriculum-kit 1.4.36 → 1.4.38
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/dist/index.cjs +338 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +189 -4
- package/dist/index.d.ts +189 -4
- package/dist/index.mjs +332 -32
- package/dist/index.mjs.map +1 -1
- package/dist/workflow/index.cjs +20 -0
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.mjs +20 -0
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +23 -22
- package/LICENSE +0 -21
package/dist/index.cjs
CHANGED
|
@@ -1532,6 +1532,8 @@ function parseLessonFlow(lessonMarkdown) {
|
|
|
1532
1532
|
purpose: cells[4] || "",
|
|
1533
1533
|
studentAction: cells[5] || "",
|
|
1534
1534
|
teacherMove: cells[6] || "",
|
|
1535
|
+
outputEvidence: cells[7] || "",
|
|
1536
|
+
lo: (cells[8] || "").replace(/\*/g, "").split(/[,;/\s]+/).map((s) => s.trim()).filter(Boolean),
|
|
1535
1537
|
time: cells[9] || cells[cells.length - 2] || "",
|
|
1536
1538
|
artifactContract: cells[cells.length - 1] || ""
|
|
1537
1539
|
});
|
|
@@ -26448,6 +26450,195 @@ function extractStandardRefs(text) {
|
|
|
26448
26450
|
return Array.from(new Set(matches));
|
|
26449
26451
|
}
|
|
26450
26452
|
|
|
26453
|
+
// src/parsers/lessonEntity.ts
|
|
26454
|
+
init_lessonFlowParser();
|
|
26455
|
+
var LessonEntitySchema = zod.z.object({
|
|
26456
|
+
lessonId: zod.z.string(),
|
|
26457
|
+
title: zod.z.string(),
|
|
26458
|
+
pedagogyModel: zod.z.string().default("5e"),
|
|
26459
|
+
estimatedDuration: zod.z.string().default(""),
|
|
26460
|
+
learningObjectives: zod.z.array(LearningObjectiveRowSchema).default([]),
|
|
26461
|
+
activitySequence: zod.z.array(ActivitySeqRowSchema).default([]),
|
|
26462
|
+
/** Header→cell rows straight from the A4 Assessment Map table (headers vary by template). */
|
|
26463
|
+
assessmentMap: zod.z.array(zod.z.record(zod.z.string())).default([]),
|
|
26464
|
+
tieredScaffolding: zod.z.object({ bronze: zod.z.string().default(""), silver: zod.z.string().default(""), gold: zod.z.string().default("") }).default({ bronze: "", silver: "", gold: "" })
|
|
26465
|
+
});
|
|
26466
|
+
var stripMd = (s) => s.replace(/\*\*/g, "").replace(/`/g, "").trim();
|
|
26467
|
+
function splitRow(line) {
|
|
26468
|
+
return line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
|
|
26469
|
+
}
|
|
26470
|
+
function toActivitySeqRows(md) {
|
|
26471
|
+
const flow = parseLessonFlow(md);
|
|
26472
|
+
const rows = [];
|
|
26473
|
+
for (const a of flow.activities) {
|
|
26474
|
+
const parsed = ActivitySeqRowSchema.safeParse({
|
|
26475
|
+
seq: a.seq,
|
|
26476
|
+
phase: a.phase,
|
|
26477
|
+
activityType: a.activityType,
|
|
26478
|
+
actor: a.actor,
|
|
26479
|
+
purpose: a.purpose,
|
|
26480
|
+
studentAction: a.studentAction,
|
|
26481
|
+
teacherMove: a.teacherMove,
|
|
26482
|
+
outputEvidence: a.outputEvidence,
|
|
26483
|
+
lo: a.lo,
|
|
26484
|
+
durationMinutes: parseInt((a.time || "").replace(/[^0-9]/g, ""), 10) || 10,
|
|
26485
|
+
artifactContract: a.artifactContract
|
|
26486
|
+
});
|
|
26487
|
+
if (parsed.success) rows.push(parsed.data);
|
|
26488
|
+
}
|
|
26489
|
+
return rows;
|
|
26490
|
+
}
|
|
26491
|
+
function parseLearningObjectives(md) {
|
|
26492
|
+
const rows = [];
|
|
26493
|
+
let inLO = false;
|
|
26494
|
+
let headerSeen = false;
|
|
26495
|
+
for (const line of md.split("\n")) {
|
|
26496
|
+
const h = line.match(/^#{2,4}\s+(.*)$/);
|
|
26497
|
+
if (h) {
|
|
26498
|
+
if (/learning\s+objectives/i.test(h[1] ?? "")) inLO = true;
|
|
26499
|
+
else if (inLO) break;
|
|
26500
|
+
continue;
|
|
26501
|
+
}
|
|
26502
|
+
if (!inLO) continue;
|
|
26503
|
+
const t = line.trim();
|
|
26504
|
+
if (!t.startsWith("|")) continue;
|
|
26505
|
+
if (/^[\s|:-]+$/.test(t)) continue;
|
|
26506
|
+
const cells = splitRow(t);
|
|
26507
|
+
if (cells.length < 4) continue;
|
|
26508
|
+
if (!headerSeen) {
|
|
26509
|
+
headerSeen = true;
|
|
26510
|
+
continue;
|
|
26511
|
+
}
|
|
26512
|
+
const parsed = LearningObjectiveRowSchema.safeParse({
|
|
26513
|
+
code: stripMd(cells[0] ?? ""),
|
|
26514
|
+
objective: stripMd(cells[1] ?? ""),
|
|
26515
|
+
evidence: stripMd(cells[2] ?? ""),
|
|
26516
|
+
successCriteria: stripMd(cells[3] ?? ""),
|
|
26517
|
+
standardRefs: cells[4] ?? "" ? cells[4].split(/[\s,;]+/).filter(Boolean) : [],
|
|
26518
|
+
conceptRefs: []
|
|
26519
|
+
});
|
|
26520
|
+
if (parsed.success) rows.push(parsed.data);
|
|
26521
|
+
}
|
|
26522
|
+
return rows;
|
|
26523
|
+
}
|
|
26524
|
+
function parseAssessmentMap(md) {
|
|
26525
|
+
const rows = [];
|
|
26526
|
+
let inMap = false;
|
|
26527
|
+
let headers = [];
|
|
26528
|
+
for (const line of md.split("\n")) {
|
|
26529
|
+
const h = line.match(/^#{2,4}\s+(.*)$/);
|
|
26530
|
+
if (h) {
|
|
26531
|
+
if (/assessment\s*map/i.test(h[1] ?? "")) inMap = true;
|
|
26532
|
+
else if (inMap) break;
|
|
26533
|
+
continue;
|
|
26534
|
+
}
|
|
26535
|
+
if (!inMap) continue;
|
|
26536
|
+
const t = line.trim();
|
|
26537
|
+
if (!t.startsWith("|")) continue;
|
|
26538
|
+
if (/^[\s|:-]+$/.test(t)) continue;
|
|
26539
|
+
const cells = splitRow(t);
|
|
26540
|
+
if (headers.length === 0) {
|
|
26541
|
+
headers = cells;
|
|
26542
|
+
continue;
|
|
26543
|
+
}
|
|
26544
|
+
const row = {};
|
|
26545
|
+
headers.forEach((hdr, i) => {
|
|
26546
|
+
row[hdr] = stripMd(cells[i] ?? "");
|
|
26547
|
+
});
|
|
26548
|
+
rows.push(row);
|
|
26549
|
+
}
|
|
26550
|
+
return rows;
|
|
26551
|
+
}
|
|
26552
|
+
function parseTieredScaffolding(md) {
|
|
26553
|
+
const lines = md.split("\n");
|
|
26554
|
+
let capture = null;
|
|
26555
|
+
for (const line of lines) {
|
|
26556
|
+
const h = line.match(/^#{2,4}\s+(.*)$/);
|
|
26557
|
+
if (h) {
|
|
26558
|
+
const isTier = /elaborate|tiered|scaffold/i.test(h[1] ?? "");
|
|
26559
|
+
if (capture && !isTier) break;
|
|
26560
|
+
if (isTier) capture = [];
|
|
26561
|
+
continue;
|
|
26562
|
+
}
|
|
26563
|
+
if (capture) capture.push(line);
|
|
26564
|
+
}
|
|
26565
|
+
const body = (capture ?? []).join("\n");
|
|
26566
|
+
const grab = (label) => {
|
|
26567
|
+
const m = body.match(new RegExp(`(?:\\ud83e\\udd49|\\ud83e\\udd48|\\ud83e\\udd47)?\\s*\\*\\*${label}:\\*\\*\\s*([^\\n]+)`, "i"));
|
|
26568
|
+
return m ? m[1].trim() : "";
|
|
26569
|
+
};
|
|
26570
|
+
return { bronze: grab("Bronze"), silver: grab("Silver"), gold: grab("Gold") };
|
|
26571
|
+
}
|
|
26572
|
+
function buildLessonEntityJson(lessonMarkdown) {
|
|
26573
|
+
const md = lessonMarkdown || "";
|
|
26574
|
+
if (!md.trim()) return null;
|
|
26575
|
+
const flow = parseLessonFlow(md);
|
|
26576
|
+
const fm = md.match(/^---\s*\n([\s\S]*?)\n---/)?.[1] ?? "";
|
|
26577
|
+
const activitySequence = toActivitySeqRows(md);
|
|
26578
|
+
const learningObjectives = parseLearningObjectives(md);
|
|
26579
|
+
if (activitySequence.length === 0 && learningObjectives.length === 0) return null;
|
|
26580
|
+
const parsed = LessonEntitySchema.safeParse({
|
|
26581
|
+
lessonId: flow.lessonId || (fm.match(/id:\s*["']?([^"'\n]+)["']?/i)?.[1]?.trim() ?? ""),
|
|
26582
|
+
title: flow.lessonTitle,
|
|
26583
|
+
pedagogyModel: flow.pedagogicalModel,
|
|
26584
|
+
estimatedDuration: flow.estimatedDuration,
|
|
26585
|
+
learningObjectives,
|
|
26586
|
+
activitySequence,
|
|
26587
|
+
assessmentMap: parseAssessmentMap(md),
|
|
26588
|
+
tieredScaffolding: parseTieredScaffolding(md)
|
|
26589
|
+
});
|
|
26590
|
+
return parsed.success ? parsed.data : null;
|
|
26591
|
+
}
|
|
26592
|
+
function renderEntitySlotsForType(entity, artifactType, maxChars = 8e3) {
|
|
26593
|
+
const type = (artifactType || "").toUpperCase().trim();
|
|
26594
|
+
const parts = [];
|
|
26595
|
+
const wantActivities = ["ACT", "GUIDE", "SLIDE", "WKS", "QUIZ"].includes(type);
|
|
26596
|
+
const wantObjectives = type !== "CODE";
|
|
26597
|
+
const wantAssessment = ["QUIZ", "WKS"].includes(type);
|
|
26598
|
+
const wantTiers = ["ACT", "CODE", "EXT", "WKS"].includes(type);
|
|
26599
|
+
if (wantObjectives && entity.learningObjectives.length > 0) {
|
|
26600
|
+
parts.push(
|
|
26601
|
+
"### Learning Objectives & Evidence\n" + entity.learningObjectives.map((o) => `- ${o.code}: ${o.objective} \u2192 Evidence: ${o.evidence} | Pass: ${o.successCriteria}`).join("\n")
|
|
26602
|
+
);
|
|
26603
|
+
}
|
|
26604
|
+
if (wantActivities && entity.activitySequence.length > 0) {
|
|
26605
|
+
const header = "| Seq | Phase | Activity | Actor | Student Action | Teacher Move | Output/Evidence | LO | Mins | Artifact Contract |";
|
|
26606
|
+
const rows = [];
|
|
26607
|
+
for (const a of entity.activitySequence) {
|
|
26608
|
+
const r = `| ${a.seq} | ${a.phase} | ${a.activityType} | ${a.actor} | ${a.studentAction} | ${a.teacherMove} | ${a.outputEvidence} | ${a.lo.join(",")} | ${a.durationMinutes} | ${a.artifactContract} |`;
|
|
26609
|
+
if (parts.join("\n\n").length + r.length > maxChars) break;
|
|
26610
|
+
rows.push(r);
|
|
26611
|
+
}
|
|
26612
|
+
if (rows.length > 0) {
|
|
26613
|
+
parts.push("### Activity Sequence\n" + [header, "|---|---|---|---|---|---|---|---|---|---|", ...rows].join("\n"));
|
|
26614
|
+
}
|
|
26615
|
+
}
|
|
26616
|
+
if (wantAssessment && entity.assessmentMap.length > 0) {
|
|
26617
|
+
const lines = entity.assessmentMap.map((r) => Object.entries(r).map(([k, v]) => `${k}: ${v}`).join(" | "));
|
|
26618
|
+
parts.push("### Assessment Map (assess exactly these)\n" + lines.join("\n"));
|
|
26619
|
+
}
|
|
26620
|
+
const t = entity.tieredScaffolding;
|
|
26621
|
+
if (wantTiers && (t.bronze || t.silver || t.gold)) {
|
|
26622
|
+
parts.push(
|
|
26623
|
+
"### Tiered task ladder\n" + [t.bronze && `- Bronze: ${t.bronze}`, t.silver && `- Silver: ${t.silver}`, t.gold && `- Gold: ${t.gold}`].filter(Boolean).join("\n")
|
|
26624
|
+
);
|
|
26625
|
+
}
|
|
26626
|
+
return parts.join("\n\n").slice(0, maxChars);
|
|
26627
|
+
}
|
|
26628
|
+
function entityRowAssignedTo(row, artifactType) {
|
|
26629
|
+
const norm2 = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
26630
|
+
const wanted = norm2(artifactType);
|
|
26631
|
+
return row.artifactContract.split(/[,;/]/).map((c) => norm2(c)).some((c) => c === wanted || c.length > 3 && (c.includes(wanted) || wanted.includes(c)));
|
|
26632
|
+
}
|
|
26633
|
+
function renderAssignedRowsTable(entity, artifactType, maxChars = 1500) {
|
|
26634
|
+
const rows = entity.activitySequence.filter((r) => entityRowAssignedTo(r, artifactType));
|
|
26635
|
+
if (rows.length === 0) return "";
|
|
26636
|
+
const header = "| Seq | Phase | Activity | Actor | Student Action | Teacher Move | Output/Evidence | LO | Mins | Artifact Contract |";
|
|
26637
|
+
const sep = "|---|---|---|---|---|---|---|---|---|---|";
|
|
26638
|
+
const body = rows.map((a) => `| ${a.seq} | ${a.phase} | ${a.activityType} | ${a.actor} | ${a.studentAction} | ${a.teacherMove} | ${a.outputEvidence} | ${a.lo.join(",")} | ${a.durationMinutes} | ${a.artifactContract} |`);
|
|
26639
|
+
return [header, sep, ...body].join("\n").slice(0, maxChars);
|
|
26640
|
+
}
|
|
26641
|
+
|
|
26451
26642
|
// src/services/contextSlots.ts
|
|
26452
26643
|
var LESSON_SLOT_BUDGETS = {
|
|
26453
26644
|
ACT: { budget: 8e3 },
|
|
@@ -26567,6 +26758,7 @@ function buildSatelliteContext(input) {
|
|
|
26567
26758
|
slcMarkdown,
|
|
26568
26759
|
symbolLedgerBlock,
|
|
26569
26760
|
pedagogyLabel,
|
|
26761
|
+
lessonEntity,
|
|
26570
26762
|
mode = "legacy"
|
|
26571
26763
|
} = input;
|
|
26572
26764
|
const type = (artifactType || "").toUpperCase().trim();
|
|
@@ -26584,13 +26776,16 @@ ${lessonExcerpt.excerpt}${symbolLedgerBlock}`;
|
|
|
26584
26776
|
verified: lessonExcerpt.verified,
|
|
26585
26777
|
sectionAware: lessonExcerpt.sectionAware,
|
|
26586
26778
|
issues: lessonExcerpt.issues,
|
|
26587
|
-
tokenEstimate: Math.round(context2.length / 4)
|
|
26779
|
+
tokenEstimate: Math.round(context2.length / 4),
|
|
26780
|
+
canonicalExcerpt: lessonExcerpt.excerpt
|
|
26588
26781
|
};
|
|
26589
26782
|
}
|
|
26590
26783
|
const blocks = [];
|
|
26591
26784
|
const issues = [];
|
|
26592
26785
|
const parts = [commonContext];
|
|
26593
26786
|
blocks.push(blockMeta("commonContext", "COMPOSITE", commonContext, true));
|
|
26787
|
+
let excerptSlot;
|
|
26788
|
+
let miniSlot;
|
|
26594
26789
|
const compositeHasKx = /###\s+KNOWLEDGE_EXPOSITION/.test(commonContext);
|
|
26595
26790
|
if (expositionContent.trim() && !compositeHasKx) {
|
|
26596
26791
|
const kxExcerpt = buildSectionAwareExcerpt(expositionContent, {
|
|
@@ -26608,28 +26803,57 @@ ${kxExcerpt.excerpt}`);
|
|
|
26608
26803
|
}
|
|
26609
26804
|
if (!KX_ONLY_TYPES.has(type)) {
|
|
26610
26805
|
const spec = LESSON_SLOT_BUDGETS[type] ?? { budget: 12e3 };
|
|
26611
|
-
|
|
26612
|
-
|
|
26613
|
-
|
|
26614
|
-
|
|
26615
|
-
|
|
26616
|
-
|
|
26617
|
-
|
|
26806
|
+
let usedEntity = false;
|
|
26807
|
+
if (lessonEntity) {
|
|
26808
|
+
const slots = renderEntitySlotsForType(lessonEntity, type, spec.budget);
|
|
26809
|
+
if (slots) {
|
|
26810
|
+
const slotBlock = `
|
|
26811
|
+
|
|
26812
|
+
[LESSON ENTITY SLOTS (structured JSON source \u2014 canonical)]:
|
|
26813
|
+
${slots}`;
|
|
26814
|
+
parts.push(slotBlock);
|
|
26815
|
+
excerptSlot = slotBlock;
|
|
26816
|
+
blocks.push(blockMeta("lessonEntity:" + type, "LESSON_JSON", slots, true));
|
|
26817
|
+
usedEntity = true;
|
|
26818
|
+
} else {
|
|
26819
|
+
issues.push(`lesson-entity:empty-slots:${type}`);
|
|
26820
|
+
}
|
|
26821
|
+
}
|
|
26822
|
+
if (!usedEntity) {
|
|
26823
|
+
const excerpt = buildSectionAwareExcerpt(lessonContent, {
|
|
26824
|
+
priorities: spec.priorities ?? ["Artifact Contract", "A. Lesson Design Plan", "B. Lesson Flow", "Learning Objectives & Evidence", "Activity Sequence"],
|
|
26825
|
+
budget: spec.budget,
|
|
26826
|
+
sectionLanguageContract: slcMarkdown,
|
|
26827
|
+
artifactType: "LESSON"
|
|
26828
|
+
});
|
|
26829
|
+
const excerptBlock = `
|
|
26618
26830
|
|
|
26619
26831
|
[CANONICAL LESSON PLAN (scoped for ${type})]:
|
|
26620
|
-
${excerpt.excerpt}
|
|
26621
|
-
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26625
|
-
if (
|
|
26626
|
-
|
|
26832
|
+
${excerpt.excerpt}`;
|
|
26833
|
+
parts.push(excerptBlock);
|
|
26834
|
+
excerptSlot = excerptBlock;
|
|
26835
|
+
blocks.push(blockMeta("lessonExcerpt:" + type, "LESSON", excerpt.excerpt, excerpt.verified, excerpt.issues));
|
|
26836
|
+
if (!excerpt.verified) issues.push(...excerpt.issues.map((i) => `lesson:${i}`));
|
|
26837
|
+
if (type === "QUIZ" || type === "WKS") {
|
|
26838
|
+
if (lessonEntity && lessonEntity.assessmentMap.length > 0) {
|
|
26839
|
+
const amJson = lessonEntity.assessmentMap.map((r) => Object.entries(r).map(([k, v]) => `${k}: ${v}`).join(" | ")).join("\n");
|
|
26840
|
+
parts.push(`
|
|
26841
|
+
|
|
26842
|
+
[ASSESSMENT MAP (criteria anchor \u2014 assess exactly these)]:
|
|
26843
|
+
${amJson}`);
|
|
26844
|
+
blocks.push(blockMeta("assessmentMap:" + type, "LESSON_JSON", amJson, true));
|
|
26845
|
+
} else {
|
|
26846
|
+
const am = extractAssessmentMap(lessonContent, 1200);
|
|
26847
|
+
if (am) {
|
|
26848
|
+
parts.push(`
|
|
26627
26849
|
|
|
26628
26850
|
[ASSESSMENT MAP (criteria anchor \u2014 assess exactly these)]:
|
|
26629
26851
|
${am}`);
|
|
26630
|
-
|
|
26631
|
-
|
|
26632
|
-
|
|
26852
|
+
blocks.push(blockMeta("assessmentMap:" + type, "LESSON", am, true));
|
|
26853
|
+
} else {
|
|
26854
|
+
issues.push(`assessment-map:unresolved:${type}`);
|
|
26855
|
+
}
|
|
26856
|
+
}
|
|
26633
26857
|
}
|
|
26634
26858
|
}
|
|
26635
26859
|
if (symbolLedgerBlock) {
|
|
@@ -26637,19 +26861,34 @@ ${am}`);
|
|
|
26637
26861
|
blocks.push(blockMeta("symbolLedger", "LESSON", symbolLedgerBlock, true));
|
|
26638
26862
|
}
|
|
26639
26863
|
} else {
|
|
26640
|
-
const
|
|
26641
|
-
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
${
|
|
26645
|
-
|
|
26646
|
-
|
|
26647
|
-
|
|
26864
|
+
const miniParts = [];
|
|
26865
|
+
if (lessonEntity) {
|
|
26866
|
+
const rowsTable = renderAssignedRowsTable(lessonEntity, type === "CODE" ? "CODE_LAB" : type, 1500);
|
|
26867
|
+
if (rowsTable) miniParts.push(`### Activity Sequence rows assigned to ${type} (canonical \u2014 do not invent a different task):
|
|
26868
|
+
${rowsTable}`);
|
|
26869
|
+
const t = lessonEntity.tieredScaffolding;
|
|
26870
|
+
if ((type === "CODE" || type === "EXT") && (t.bronze || t.silver || t.gold)) {
|
|
26871
|
+
miniParts.push(
|
|
26872
|
+
"### Tiered task ladder (from LESSON Elaborate phase):\n" + [t.bronze && `- Bronze: ${t.bronze}`, t.silver && `- Silver: ${t.silver}`, t.gold && `- Gold: ${t.gold}`].filter(Boolean).join("\n")
|
|
26873
|
+
);
|
|
26874
|
+
}
|
|
26875
|
+
}
|
|
26876
|
+
if (miniParts.length === 0) {
|
|
26877
|
+
const contractRows = extractActivityContractRows(lessonContent, type === "CODE" ? "CODE_LAB" : type, 1500);
|
|
26878
|
+
const tierBlock = type === "CODE" || type === "EXT" ? extractTieredScaffoldingBlock(lessonContent, 900) : "";
|
|
26879
|
+
if (contractRows) miniParts.push(`### Activity Sequence rows assigned to ${type} (canonical \u2014 do not invent a different task):
|
|
26880
|
+
${contractRows}`);
|
|
26881
|
+
if (tierBlock) miniParts.push(`### Tiered task ladder (from LESSON Elaborate phase):
|
|
26882
|
+
${tierBlock}`);
|
|
26883
|
+
}
|
|
26884
|
+
const mini = miniParts.join("\n\n");
|
|
26648
26885
|
if (mini) {
|
|
26649
|
-
|
|
26886
|
+
const miniBlock = `
|
|
26650
26887
|
|
|
26651
26888
|
[LESSON ACTIVITY CONTRACT (mini-slot)]:
|
|
26652
|
-
${mini}
|
|
26889
|
+
${mini}`;
|
|
26890
|
+
parts.push(miniBlock);
|
|
26891
|
+
miniSlot = miniBlock;
|
|
26653
26892
|
blocks.push(blockMeta("activityContract:" + type, "LESSON", mini, true));
|
|
26654
26893
|
} else {
|
|
26655
26894
|
issues.push(`activity-contract:unresolved:${type}`);
|
|
@@ -26667,9 +26906,36 @@ ${mini}`);
|
|
|
26667
26906
|
verified: blocks.filter((b) => b.slot !== "commonContext").every((b) => b.verified),
|
|
26668
26907
|
sectionAware: blocks.some((b) => b.slot.startsWith("lessonExcerpt") || b.slot.startsWith("kxExcerpt")),
|
|
26669
26908
|
issues,
|
|
26670
|
-
tokenEstimate: Math.round(context.length / 4)
|
|
26909
|
+
tokenEstimate: Math.round(context.length / 4),
|
|
26910
|
+
// Judge ground truth = exactly what THIS type consumed (scoped or mini slot).
|
|
26911
|
+
canonicalExcerpt: (miniSlot ?? excerptSlot ?? lessonExcerpt.excerpt).trim()
|
|
26671
26912
|
};
|
|
26672
26913
|
}
|
|
26914
|
+
var ACTIVITY_ALIGNMENT_LOG_ONLY_UNTIL = /* @__PURE__ */ new Date("2026-09-23T00:00:00Z");
|
|
26915
|
+
function isActivityAlignmentLogOnly(now = /* @__PURE__ */ new Date()) {
|
|
26916
|
+
const env = (process.env.DRIFT_ALIGNMENT_LOG_ONLY ?? "").toLowerCase().trim();
|
|
26917
|
+
if (env === "false" || env === "0") return false;
|
|
26918
|
+
if (env === "true" || env === "1") return true;
|
|
26919
|
+
return now < ACTIVITY_ALIGNMENT_LOG_ONLY_UNTIL;
|
|
26920
|
+
}
|
|
26921
|
+
function evaluateActivityAlignment(canonicalExcerpt, generatedContent, now = /* @__PURE__ */ new Date()) {
|
|
26922
|
+
const mode = isActivityAlignmentLogOnly(now) ? "log_only" : "enforcing";
|
|
26923
|
+
if (!canonicalExcerpt || !canonicalExcerpt.trim()) {
|
|
26924
|
+
return { checked: false, passed: null, matchedTokens: [], missingTokens: [], mode };
|
|
26925
|
+
}
|
|
26926
|
+
const content = (generatedContent || "").toLowerCase();
|
|
26927
|
+
const stripped = canonicalExcerpt.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
26928
|
+
const latin = Array.from(new Set(stripped.match(/[a-z][a-z0-9_]{3,}/g) ?? []));
|
|
26929
|
+
const cjk = Array.from(new Set(canonicalExcerpt.match(/[\u4e00-\u9fff]{2,}/g) ?? []));
|
|
26930
|
+
const tokens = [...latin, ...cjk];
|
|
26931
|
+
if (tokens.length === 0) {
|
|
26932
|
+
return { checked: false, passed: null, matchedTokens: [], missingTokens: [], mode };
|
|
26933
|
+
}
|
|
26934
|
+
const matchedTokens = tokens.filter((t) => content.includes(t));
|
|
26935
|
+
const missingTokens = tokens.filter((t) => !content.includes(t));
|
|
26936
|
+
const passed = matchedTokens.length > 0;
|
|
26937
|
+
return { checked: true, passed, matchedTokens: matchedTokens.slice(0, 10), missingTokens: missingTokens.slice(0, 10), mode };
|
|
26938
|
+
}
|
|
26673
26939
|
|
|
26674
26940
|
// src/services/lessonProductionService.ts
|
|
26675
26941
|
var __filename2 = typeof (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) === "string" && typeof url.fileURLToPath === "function" ? url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))) : "";
|
|
@@ -27309,7 +27575,9 @@ ${sg}${standardsBlock}${glossaryBlock}${buildGroundTruthBlock(includeKx)}${sessi
|
|
|
27309
27575
|
});
|
|
27310
27576
|
const producedArtifacts = [];
|
|
27311
27577
|
const lessonRelPath = `_content/${unitCode}/LESSON_${lessonCode}.md`;
|
|
27578
|
+
const lessonEntityRelPath = `_content/${unitCode}/LESSON_${lessonCode}.json`;
|
|
27312
27579
|
const existingLessonContent = await storage.readArtifact(projectId, lessonRelPath);
|
|
27580
|
+
let lessonEntity = buildLessonEntityJson(existingLessonContent || "");
|
|
27313
27581
|
let lessonContent = existingLessonContent || "";
|
|
27314
27582
|
if (artifactScope.includes("LESSON") && (!existingLessonContent || force || isStaleVsPlan(existingLessonContent))) {
|
|
27315
27583
|
if (existingLessonContent && !force && isStaleVsPlan(existingLessonContent)) {
|
|
@@ -27385,7 +27653,12 @@ Fix ALL issues above and output the complete corrected document.` }],
|
|
|
27385
27653
|
} else {
|
|
27386
27654
|
lessonContent = lintReport.autoFixedContent || rawLesson;
|
|
27387
27655
|
}
|
|
27388
|
-
|
|
27656
|
+
const stampedLesson = stampPlanHash(lessonContent);
|
|
27657
|
+
await storage.saveArtifact(projectId, lessonRelPath, stampedLesson);
|
|
27658
|
+
lessonEntity = buildLessonEntityJson(stampedLesson);
|
|
27659
|
+
if (lessonEntity) {
|
|
27660
|
+
await storage.saveArtifact(projectId, lessonEntityRelPath, JSON.stringify({ planHash: currentPlanHash ?? null, entity: lessonEntity }, null, 2));
|
|
27661
|
+
}
|
|
27389
27662
|
producedArtifacts.push(`LESSON_${lessonCode}.md`);
|
|
27390
27663
|
}
|
|
27391
27664
|
const contentHash = lessonContent ? computeContentHash(lessonContent) : void 0;
|
|
@@ -27694,6 +27967,7 @@ ${currentContent}` }],
|
|
|
27694
27967
|
const routingMode = options.contextRoutingMode ?? "legacy";
|
|
27695
27968
|
const kxFreeCommonContext = routingMode === "hybrid" ? assembleCommonContext(effectiveStyleGuide, false) : "";
|
|
27696
27969
|
const satelliteContexts = {};
|
|
27970
|
+
const satelliteContextMeta = {};
|
|
27697
27971
|
const satelliteContextFor = (artifactType) => {
|
|
27698
27972
|
const key = artifactType.toUpperCase();
|
|
27699
27973
|
if (!satelliteContexts[key]) {
|
|
@@ -27706,9 +27980,11 @@ ${currentContent}` }],
|
|
|
27706
27980
|
slcMarkdown,
|
|
27707
27981
|
symbolLedgerBlock,
|
|
27708
27982
|
pedagogyLabel,
|
|
27983
|
+
lessonEntity,
|
|
27709
27984
|
mode: routingMode
|
|
27710
27985
|
});
|
|
27711
27986
|
satelliteContexts[key] = built.context;
|
|
27987
|
+
satelliteContextMeta[key] = built;
|
|
27712
27988
|
onProgress?.(
|
|
27713
27989
|
"@content",
|
|
27714
27990
|
`[CONTEXT] ${key} satellite context: ${built.context.length} chars (${built.blocks.map((b) => `${b.slot}:${b.chars}`).join(", ")})`,
|
|
@@ -27736,6 +28012,30 @@ ${currentContent}` }],
|
|
|
27736
28012
|
}
|
|
27737
28013
|
});
|
|
27738
28014
|
}
|
|
28015
|
+
const slotMeta = satelliteContextMeta[sat.toUpperCase()];
|
|
28016
|
+
if (slotMeta) {
|
|
28017
|
+
const alignment = evaluateActivityAlignment(slotMeta.canonicalExcerpt, content);
|
|
28018
|
+
if (alignment.checked && alignment.passed === false) {
|
|
28019
|
+
const note = `activity-alignment drift vs ${sat} contract slot (matched: ${alignment.matchedTokens.join(", ") || "none"}); canonical tokens absent from output`;
|
|
28020
|
+
if (alignment.mode === "enforcing") {
|
|
28021
|
+
const critique = validatorRepairPrompt([{ code: "scope-drift", detail: note, evidence: alignment.missingTokens }]);
|
|
28022
|
+
onProgress?.("@reviewer", `\u26D4 ${sat} activity-alignment drift FAIL: ${note}`);
|
|
28023
|
+
return storage.updateArtifactState(projectId, lessonCode, sat, {
|
|
28024
|
+
state: "rejected",
|
|
28025
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28026
|
+
contentHash: computeContentHash(content),
|
|
28027
|
+
review: {
|
|
28028
|
+
decision: "NEEDS_REVISION",
|
|
28029
|
+
reviewedBy: "@heuristic-linter",
|
|
28030
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28031
|
+
score: 0,
|
|
28032
|
+
critique
|
|
28033
|
+
}
|
|
28034
|
+
});
|
|
28035
|
+
}
|
|
28036
|
+
onProgress?.("@reviewer", `\u{1F9ED} [log-only] ${sat} activity-alignment drift: ${note}`);
|
|
28037
|
+
}
|
|
28038
|
+
}
|
|
27739
28039
|
return judgeSatelliteArtifact({
|
|
27740
28040
|
storage,
|
|
27741
28041
|
projectId,
|
|
@@ -27748,7 +28048,7 @@ ${currentContent}` }],
|
|
|
27748
28048
|
onProgress,
|
|
27749
28049
|
targetLang,
|
|
27750
28050
|
canonicalLessonContent: lessonContent,
|
|
27751
|
-
canonicalLessonExcerpt: lessonExcerpt
|
|
28051
|
+
canonicalLessonExcerpt: slotMeta?.canonicalExcerpt ?? lessonExcerpt
|
|
27752
28052
|
});
|
|
27753
28053
|
};
|
|
27754
28054
|
const actRelPath = `_content/${unitCode}/ACT_${lessonCode}.md`;
|
|
@@ -33227,6 +33527,7 @@ exports.LLMJudgeEngine = LLMJudgeEngine;
|
|
|
33227
33527
|
exports.LabTierTaskSchema = LabTierTaskSchema;
|
|
33228
33528
|
exports.LearningObjectiveInputSchema = LearningObjectiveInputSchema;
|
|
33229
33529
|
exports.LearningObjectiveRowSchema = LearningObjectiveRowSchema;
|
|
33530
|
+
exports.LessonEntitySchema = LessonEntitySchema;
|
|
33230
33531
|
exports.LessonFlowPhaseSchema = LessonFlowPhaseSchema;
|
|
33231
33532
|
exports.LessonPlan5ESchema = LessonPlan5ESchema;
|
|
33232
33533
|
exports.LessonPlanEDPSchema = LessonPlanEDPSchema;
|
|
@@ -33346,6 +33647,7 @@ exports.buildHtmlDeckSlidePrompt = buildHtmlDeckSlidePrompt;
|
|
|
33346
33647
|
exports.buildImagePrompt = buildImagePrompt;
|
|
33347
33648
|
exports.buildJudgePrompt = buildJudgePrompt;
|
|
33348
33649
|
exports.buildLanguageDirective = buildLanguageDirective;
|
|
33650
|
+
exports.buildLessonEntityJson = buildLessonEntityJson;
|
|
33349
33651
|
exports.buildLessonExcerpt = buildLessonExcerpt;
|
|
33350
33652
|
exports.buildLessonMasterPrompt = buildLessonMasterPrompt;
|
|
33351
33653
|
exports.buildMarpMarkdownSlidePrompt = buildMarpMarkdownSlidePrompt;
|
|
@@ -33384,6 +33686,8 @@ exports.dropCyclicConceptEdges = dropCyclicConceptEdges;
|
|
|
33384
33686
|
exports.emitUsage = emitUsage;
|
|
33385
33687
|
exports.ensureExpositionForLesson = ensureExpositionForLesson;
|
|
33386
33688
|
exports.ensureKnowledgeExposition = ensureKnowledgeExposition;
|
|
33689
|
+
exports.entityRowAssignedTo = entityRowAssignedTo;
|
|
33690
|
+
exports.evaluateActivityAlignment = evaluateActivityAlignment;
|
|
33387
33691
|
exports.evaluateStandardsCoverage = evaluateStandardsCoverage;
|
|
33388
33692
|
exports.executeCurriculumCommand = executeCurriculumCommand;
|
|
33389
33693
|
exports.executeSlideProductionWorkflow = executeSlideProductionWorkflow;
|
|
@@ -33440,6 +33744,7 @@ exports.importRoadmapToProject = importRoadmapToProject;
|
|
|
33440
33744
|
exports.ingestProjectGraphIntoProject = ingestProjectGraphIntoProject;
|
|
33441
33745
|
exports.initializeProjectInStorage = initializeProjectInStorage;
|
|
33442
33746
|
exports.injectMediaIntoMarkdown = injectMediaIntoMarkdown;
|
|
33747
|
+
exports.isActivityAlignmentLogOnly = isActivityAlignmentLogOnly;
|
|
33443
33748
|
exports.isExpositionFresh = isExpositionFresh;
|
|
33444
33749
|
exports.isModelAllowed = isModelAllowed;
|
|
33445
33750
|
exports.isProviderEnabled = isProviderEnabled;
|
|
@@ -33461,6 +33766,8 @@ exports.produceSingleLesson = produceSingleLesson;
|
|
|
33461
33766
|
exports.publishToGitHub = publishToGitHub;
|
|
33462
33767
|
exports.publishToSupabase = publishToSupabase;
|
|
33463
33768
|
exports.rankGenCandidates = rankGenCandidates;
|
|
33769
|
+
exports.renderAssignedRowsTable = renderAssignedRowsTable;
|
|
33770
|
+
exports.renderEntitySlotsForType = renderEntitySlotsForType;
|
|
33464
33771
|
exports.renderFrameworkFromPlan = renderFrameworkFromPlan;
|
|
33465
33772
|
exports.renderHorizonPromptBlock = renderHorizonPromptBlock;
|
|
33466
33773
|
exports.renderMediaPlaceholder = renderMediaPlaceholder;
|