Download src/lib/teaching/physicsLessonSeedFactory.ts from asnannp/DocDoeAI: direct link, hf CLI and curl.
- Browser
- Download file 16.6 kB
-
https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/lib/teaching/physicsLessonSeedFactory.ts
- Command line
-
hf download hf://spaces/asnannp/DocDoeAI/src/lib/teaching/physicsLessonSeedFactory.ts
-
curl -L -o physicsLessonSeedFactory.ts https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/lib/teaching/physicsLessonSeedFactory.ts
16.6 kB
| import { | |
| chaptersWithPhysicsSeeds, | |
| getAllLessonSeeds, | |
| type LessonSeedContentType, | |
| type TuitionLessonSeed, | |
| } from "./physicsLessonSeeds"; | |
| import { | |
| getPhysicsMissionBlueprint, | |
| getPhysicsMissionBlueprints, | |
| getMissingBlueprintRequirements, | |
| type PhysicsMissionBlueprintType, | |
| } from "./physicsMissionBlueprints"; | |
| import { getPhysicsSourcePack, getPhysicsSourcePacks, type PhysicsChapterSourcePack } from "./physicsSourcePacks"; | |
| import { evaluateMagneticEffectCoverageGate } from "./magneticEffectCoverageGate"; | |
| /** | |
| * Curation status distinguishes *source readiness* from *teachable curation*: | |
| * - "curated" β final teachable seeds exist and are registered. | |
| * - "curation_ready" β source repaired + evidence gate passed; final seeds MISSING (Phase 6J). | |
| * - "draftable" β source strong enough to draft review-only, not gate-passed. | |
| * - "blocked" β source too thin; needs manual source repair first. | |
| */ | |
| export type ChapterCurationStatus = "curated" | "curation_ready" | "draftable" | "blocked"; | |
| export type DraftSeedStatus = | |
| | "curated" | |
| | "draft_needs_review" | |
| | "blocked_missing_source" | |
| | "blocked_missing_required_sections"; | |
| export type PhysicsDraftLessonSeed = { | |
| missionId: string; | |
| chapterId: string; | |
| chapterTitle: string; | |
| missionTitle: string; | |
| status: DraftSeedStatus; | |
| canTeach: boolean; | |
| missingFields: string[]; | |
| warnings: string[]; | |
| seed?: TuitionLessonSeed; | |
| }; | |
| export type PhysicsSeedCoverage = { | |
| chapterId: string; | |
| chapterTitle: string; | |
| curatedSeedCount: number; | |
| missionIds: string[]; | |
| missionTypes: LessonSeedContentType[]; | |
| }; | |
| export type PhysicsDraftSeedPlan = { | |
| chapterId: string; | |
| chapterTitle: string; | |
| status: DraftSeedStatus; | |
| sourceConfidence: PhysicsChapterSourcePack["coverageConfidence"] | "missing"; | |
| recommendedBlueprints: PhysicsMissionBlueprintType[]; | |
| missingSignals: string[]; | |
| warnings: string[]; | |
| nextAction: string; | |
| }; | |
| export type PhysicsSeedFactoryReport = { | |
| totalPhysicsChapters: number; | |
| curatedChapters: string[]; | |
| uncuratedChapters: string[]; | |
| blockedChapters: Array<{ chapterId: string; reason: string }>; | |
| draftableChapters: string[]; | |
| /** Chapters whose thin extraction was repaired by a manual evidence override (Phase 6I). */ | |
| sourceRepairedChapters: string[]; | |
| /** Source-repaired + gate-passed chapters awaiting final seed authoring (not teachable yet). */ | |
| curationReadyChapters: string[]; | |
| nextRecommendedBatch: string[]; | |
| /** Human-readable next action so source repair is never confused with final curation. */ | |
| nextRecommendedAction: string; | |
| coverageByChapter: Array<{ | |
| chapterId: string; | |
| chapterTitle: string; | |
| sourceConfidence: PhysicsChapterSourcePack["coverageConfidence"]; | |
| curatedSeedCount: number; | |
| curationStatus: ChapterCurationStatus; | |
| sourceRepaired: boolean; | |
| finalSeedsPresent: boolean; | |
| missingMissionTypes: PhysicsMissionBlueprintType[]; | |
| warnings: string[]; | |
| }>; | |
| }; | |
| export type PhysicsSeedFactoryStatus = { | |
| officialCuratedChapters: string[]; | |
| uncuratedChapters: string[]; | |
| draftableChapters: string[]; | |
| blockedChapters: Array<{ chapterId: string; reason: string }>; | |
| officialSeedCount: number; | |
| }; | |
| function unique<T>(values: T[]): T[] { | |
| return Array.from(new Set(values)); | |
| } | |
| function curatedSeedsFor(chapterId: string): TuitionLessonSeed[] { | |
| return getAllLessonSeeds().filter((seed) => seed.chapterId === chapterId); | |
| } | |
| function missionTypeFromContentType(contentType: LessonSeedContentType): PhysicsMissionBlueprintType { | |
| if (contentType === "concept") return "concept"; | |
| if (contentType === "diagram") return "diagram"; | |
| if (contentType === "formula") return "formula"; | |
| if (contentType === "numerical") return "numerical"; | |
| if (contentType === "exam_answer") return "exam_answer"; | |
| if (contentType === "revision") return "revision"; | |
| if (contentType === "pyq_placeholder") return "pyq_placeholder"; | |
| return "concept"; | |
| } | |
| function recommendedBlueprintsFor(pack: PhysicsChapterSourcePack): PhysicsMissionBlueprintType[] { | |
| const signals = pack.extractedSignals; | |
| const recommended: PhysicsMissionBlueprintType[] = []; | |
| if (signals.definitions.length || signals.keyTerms.length) recommended.push("concept"); | |
| if (signals.diagrams.length) recommended.push("diagram"); | |
| if (signals.formulas.length) recommended.push("formula"); | |
| if (signals.formulas.length && signals.numericalPatterns.length) recommended.push("numerical"); | |
| if (signals.possibleQuestions.length) recommended.push("exam_answer"); | |
| if (signals.definitions.length || signals.formulas.length || signals.possibleQuestions.length) recommended.push("revision"); | |
| return recommended.length ? unique(recommended) : ["concept", "exam_answer", "revision"]; | |
| } | |
| function missingSignalsFor(pack: PhysicsChapterSourcePack, blueprint: PhysicsMissionBlueprintType): string[] { | |
| const signals = pack.extractedSignals; | |
| const missing: string[] = []; | |
| const requiredSignals = getPhysicsMissionBlueprint(blueprint).requiredSignals; | |
| if (requiredSignals.includes("definitions") && signals.definitions.length === 0) missing.push("definitions"); | |
| if (requiredSignals.includes("keyTerms") && signals.keyTerms.length === 0) missing.push("key terms"); | |
| if (requiredSignals.includes("formulas") && signals.formulas.length === 0) missing.push("formulas"); | |
| if (requiredSignals.includes("visualBoard") && signals.diagrams.length === 0) missing.push("visual board frames"); | |
| if (requiredSignals.includes("solvedExample") && signals.numericalPatterns.length === 0) missing.push("solved numerical example"); | |
| if (requiredSignals.includes("examAnswers") && signals.possibleQuestions.length === 0) missing.push("exam answer questions"); | |
| if (requiredSignals.includes("keywords") && signals.keyTerms.length === 0) missing.push("exam keywords"); | |
| if (requiredSignals.includes("flashcards") && signals.definitions.length === 0) missing.push("flashcards/revision anchors"); | |
| if (requiredSignals.includes("weakAreaTags") && signals.keyTerms.length === 0) missing.push("weak area tags"); | |
| if (requiredSignals.includes("curatedPyqEvidence")) missing.push("curated PYQ evidence"); | |
| return unique(missing); | |
| } | |
| function draftMissingFields(pack: PhysicsChapterSourcePack, blueprint: PhysicsMissionBlueprintType): string[] { | |
| return unique([ | |
| "human-authored 11-step lesson seed", | |
| "human review approval", | |
| ...missingSignalsFor(pack, blueprint), | |
| ...getMissingBlueprintRequirements(blueprint, { | |
| sourceRefs: pack.sourceRefs, | |
| formulas: pack.extractedSignals.formulas.map((formula) => ({ formula, symbols: [] })), | |
| solvedExamples: pack.extractedSignals.numericalPatterns, | |
| visualFrames: pack.extractedSignals.diagrams, | |
| examAnswers: pack.extractedSignals.possibleQuestions.map(() => ({ keywords: pack.extractedSignals.keyTerms })), | |
| flashcards: pack.extractedSignals.definitions, | |
| weakAreaTags: pack.extractedSignals.keyTerms, | |
| pyqEvidenceStatus: "not_curated", | |
| }), | |
| ]); | |
| } | |
| export function getCuratedPhysicsSeedCoverage(): PhysicsSeedCoverage[] { | |
| const byChapter = new Map<string, TuitionLessonSeed[]>(); | |
| for (const seed of getAllLessonSeeds()) { | |
| byChapter.set(seed.chapterId, [...(byChapter.get(seed.chapterId) ?? []), seed]); | |
| } | |
| return Array.from(byChapter.entries()).map(([chapterId, seeds]) => ({ | |
| chapterId, | |
| chapterTitle: seeds[0]?.chapterTitle ?? chapterId, | |
| curatedSeedCount: seeds.length, | |
| missionIds: seeds.map((seed) => seed.missionId), | |
| missionTypes: unique(seeds.map((seed) => seed.contentType)), | |
| })); | |
| } | |
| export function getUncuratedPhysicsChapters(): PhysicsChapterSourcePack[] { | |
| const curated = new Set(chaptersWithPhysicsSeeds()); | |
| return getPhysicsSourcePacks().filter((pack) => !curated.has(pack.chapterId)); | |
| } | |
| export function createPhysicsDraftSeedPlan(chapterId: string): PhysicsDraftSeedPlan { | |
| const pack = getPhysicsSourcePack(chapterId); | |
| if (!pack) { | |
| return { | |
| chapterId, | |
| chapterTitle: chapterId, | |
| status: "blocked_missing_source", | |
| sourceConfidence: "missing", | |
| recommendedBlueprints: [], | |
| missingSignals: ["source pack"], | |
| warnings: ["No Physics source pack exists for this chapter."], | |
| nextAction: "Locate source metadata before drafting any lesson seed.", | |
| }; | |
| } | |
| if (chaptersWithPhysicsSeeds().includes(chapterId)) { | |
| return { | |
| chapterId, | |
| chapterTitle: pack.chapterTitle, | |
| status: "curated", | |
| sourceConfidence: pack.coverageConfidence, | |
| recommendedBlueprints: [], | |
| missingSignals: [], | |
| warnings: pack.warnings, | |
| nextAction: "Already curated. Do not regenerate from the factory.", | |
| }; | |
| } | |
| const recommendedBlueprints = recommendedBlueprintsFor(pack); | |
| const missingSignals = unique(recommendedBlueprints.flatMap((blueprint) => missingSignalsFor(pack, blueprint))); | |
| const blocked = pack.coverageConfidence === "low"; | |
| return { | |
| chapterId, | |
| chapterTitle: pack.chapterTitle, | |
| status: blocked ? "blocked_missing_required_sections" : "draft_needs_review", | |
| sourceConfidence: pack.coverageConfidence, | |
| recommendedBlueprints, | |
| missingSignals, | |
| warnings: pack.warnings, | |
| nextAction: blocked | |
| ? "Create a human curation TODO before drafting. Extracted signals are too thin for safe seed drafting." | |
| : "Draft review-only seeds from the recommended blueprints; keep canTeach=false until human-authored content validates.", | |
| }; | |
| } | |
| export function createPhysicsDraftSeedsForChapter(chapterId: string): PhysicsDraftLessonSeed[] { | |
| const pack = getPhysicsSourcePack(chapterId); | |
| if (!pack) { | |
| return [ | |
| { | |
| missionId: "TODO", | |
| chapterId, | |
| chapterTitle: chapterId, | |
| missionTitle: "Source pack missing", | |
| status: "blocked_missing_source", | |
| canTeach: false, | |
| missingFields: ["source pack", "sourceRefs"], | |
| warnings: ["No Physics source pack exists for this chapter."], | |
| }, | |
| ]; | |
| } | |
| const curatedSeeds = curatedSeedsFor(chapterId); | |
| if (curatedSeeds.length > 0) { | |
| return curatedSeeds.map((seed) => ({ | |
| missionId: seed.missionId, | |
| chapterId: seed.chapterId, | |
| chapterTitle: seed.chapterTitle, | |
| missionTitle: seed.missionTitle, | |
| status: "curated", | |
| canTeach: seed.canTeach, | |
| missingFields: [], | |
| warnings: seed.qualityFlags.reason ? [seed.qualityFlags.reason] : [], | |
| seed, | |
| })); | |
| } | |
| const plan = createPhysicsDraftSeedPlan(chapterId); | |
| if (plan.status === "blocked_missing_required_sections") { | |
| return [ | |
| { | |
| missionId: "TODO", | |
| chapterId: pack.chapterId, | |
| chapterTitle: pack.chapterTitle, | |
| missionTitle: `Review source pack for ${pack.chapterTitle}`, | |
| status: "blocked_missing_required_sections", | |
| canTeach: false, | |
| missingFields: unique(["strong source signals", ...plan.missingSignals, "human-authored 11-step lesson seed"]), | |
| warnings: plan.warnings, | |
| }, | |
| ]; | |
| } | |
| return plan.recommendedBlueprints.map((blueprint, index) => ({ | |
| missionId: `D${index + 1}`, | |
| chapterId: pack.chapterId, | |
| chapterTitle: pack.chapterTitle, | |
| missionTitle: `${getPhysicsMissionBlueprint(blueprint).title} - ${pack.chapterTitle}`, | |
| status: "draft_needs_review", | |
| canTeach: false, | |
| missingFields: draftMissingFields(pack, blueprint), | |
| warnings: unique([ | |
| ...plan.warnings, | |
| "Draft output is review-only and is not registered in Tuition Mode.", | |
| "No official canTeach=true seed is produced by the factory.", | |
| ]), | |
| })); | |
| } | |
| /** | |
| * Curation status per chapter. Distinguishes source repair (Phase 6I) from final | |
| * teachable curation. A source-repaired chapter that passes its evidence gate is | |
| * "curation_ready" β its final seeds are still MISSING and it is NOT teachable. | |
| */ | |
| function curationStatusFor(pack: PhysicsChapterSourcePack, hasSeeds: boolean): ChapterCurationStatus { | |
| if (hasSeeds) return "curated"; | |
| if (pack.sourceRepaired) { | |
| if (pack.chapterId === "phy-p1-c4") { | |
| const gate = evaluateMagneticEffectCoverageGate(); | |
| if (gate.status === "curation_ready") return "curation_ready"; | |
| if (gate.status === "draftable") return "draftable"; | |
| return "blocked"; | |
| } | |
| return "draftable"; | |
| } | |
| return pack.coverageConfidence === "low" ? "blocked" : "draftable"; | |
| } | |
| export function createPhysicsBatchCurationReport(): PhysicsSeedFactoryReport { | |
| const packs = getPhysicsSourcePacks(); | |
| const coverage = getCuratedPhysicsSeedCoverage(); | |
| const curatedByChapter = new Map(coverage.map((item) => [item.chapterId, item])); | |
| const curatedChapters = coverage.map((item) => item.chapterId); | |
| const uncurated = packs.filter((pack) => !curatedByChapter.has(pack.chapterId)); | |
| const statusByChapter = new Map<string, ChapterCurationStatus>( | |
| packs.map((pack) => [pack.chapterId, curationStatusFor(pack, curatedByChapter.has(pack.chapterId))]), | |
| ); | |
| const blockedChapters = packs | |
| .filter((pack) => statusByChapter.get(pack.chapterId) === "blocked") | |
| .map((pack) => ({ chapterId: pack.chapterId, reason: pack.warnings[0] ?? "Source too thin to draft." })); | |
| const draftableChapters = packs | |
| .filter((pack) => statusByChapter.get(pack.chapterId) === "draftable") | |
| .map((pack) => pack.chapterId); | |
| const curationReadyChapters = packs | |
| .filter((pack) => statusByChapter.get(pack.chapterId) === "curation_ready") | |
| .map((pack) => pack.chapterId); | |
| const sourceRepairedChapters = packs.filter((pack) => pack.sourceRepaired).map((pack) => pack.chapterId); | |
| // Priority of the next real work: | |
| // 1. curation_ready chapters β author final teaching seeds (Phase 6J). | |
| // 2. draftable chapters β draft review-only seeds. | |
| // 3. blocked chapters β repair the source first. | |
| let nextRecommendedBatch: string[]; | |
| let nextRecommendedAction: string; | |
| if (curationReadyChapters.length > 0) { | |
| nextRecommendedBatch = curationReadyChapters.slice(0, 2); | |
| nextRecommendedAction = `Phase 6J: curate final lesson seeds for ${curationReadyChapters.join(", ")} (source repaired, final seeds missing, not teachable yet).`; | |
| } else if (draftableChapters.length > 0) { | |
| nextRecommendedBatch = draftableChapters.slice(0, 2); | |
| nextRecommendedAction = `Draft review-only seeds for ${draftableChapters.slice(0, 2).join(", ")}.`; | |
| } else if (blockedChapters.length > 0) { | |
| nextRecommendedBatch = blockedChapters.map((chapter) => chapter.chapterId).slice(0, 2); | |
| nextRecommendedAction = `Repair the source layer for ${blockedChapters.map((c) => c.chapterId).slice(0, 2).join(", ")} before drafting.`; | |
| } else { | |
| nextRecommendedBatch = []; | |
| nextRecommendedAction = | |
| "Physics is complete β all 7 chapters are curated. Next: a Physics QA pass, or begin Chemistry source repair/curation."; | |
| } | |
| return { | |
| totalPhysicsChapters: packs.length, | |
| curatedChapters, | |
| uncuratedChapters: uncurated.map((pack) => pack.chapterId), | |
| blockedChapters, | |
| draftableChapters, | |
| sourceRepairedChapters, | |
| curationReadyChapters, | |
| nextRecommendedBatch, | |
| nextRecommendedAction, | |
| coverageByChapter: packs.map((pack) => { | |
| const item = curatedByChapter.get(pack.chapterId); | |
| const existingMissionTypes = new Set((item?.missionTypes ?? []).map(missionTypeFromContentType)); | |
| const missingMissionTypes = getPhysicsMissionBlueprints() | |
| .filter((blueprint) => blueprint.canBeTeachable) | |
| .map((blueprint) => blueprint.type) | |
| .filter((type) => !existingMissionTypes.has(type)); | |
| return { | |
| chapterId: pack.chapterId, | |
| chapterTitle: pack.chapterTitle, | |
| sourceConfidence: pack.coverageConfidence, | |
| curatedSeedCount: item?.curatedSeedCount ?? 0, | |
| curationStatus: statusByChapter.get(pack.chapterId) ?? "blocked", | |
| sourceRepaired: Boolean(pack.sourceRepaired), | |
| finalSeedsPresent: (item?.curatedSeedCount ?? 0) > 0, | |
| missingMissionTypes, | |
| warnings: pack.warnings, | |
| }; | |
| }), | |
| }; | |
| } | |
| export function getPhysicsSeedFactoryStatus(): PhysicsSeedFactoryStatus { | |
| const report = createPhysicsBatchCurationReport(); | |
| return { | |
| officialCuratedChapters: report.curatedChapters, | |
| uncuratedChapters: report.uncuratedChapters, | |
| draftableChapters: report.draftableChapters, | |
| blockedChapters: report.blockedChapters, | |
| // Day 20 β the seed pool now includes the first Chemistry draft; this | |
| // factory reports PHYSICS curation status, so count Physics seeds only. | |
| officialSeedCount: getAllLessonSeeds().filter((seed) => seed.subject === "Physics").length, | |
| }; | |
| } | |