@thanh01.pmt/domain-kit 0.4.0 → 0.5.0
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/{chunk-PKUEOSZ3.mjs → chunk-E4GCCWJO.mjs} +11 -2
- package/dist/chunk-E4GCCWJO.mjs.map +1 -0
- package/dist/{chunk-LZQLLAYP.mjs → chunk-G7HLFMD2.mjs} +5 -5
- package/dist/{chunk-LZQLLAYP.mjs.map → chunk-G7HLFMD2.mjs.map} +1 -1
- package/dist/{chunk-QJF4QCBJ.mjs → chunk-TWKIVUTQ.mjs} +8 -3
- package/dist/chunk-TWKIVUTQ.mjs.map +1 -0
- package/dist/{chunk-HILSUZOF.mjs → chunk-TYXSJUQU.mjs} +99 -8
- package/dist/chunk-TYXSJUQU.mjs.map +1 -0
- package/dist/curriculumFeedEmitter-T7NUBLAM.mjs +4 -0
- package/dist/{curriculumFeedEmitter-6IK6PFDH.mjs.map → curriculumFeedEmitter-T7NUBLAM.mjs.map} +1 -1
- package/dist/{curriculumFeedSchema-B66H3gEV.d.ts → curriculumFeedSchema-DUFwFyr2.d.cts} +56 -0
- package/dist/{curriculumFeedSchema-B66H3gEV.d.cts → curriculumFeedSchema-DUFwFyr2.d.ts} +56 -0
- package/dist/feed/index.cjs +14 -0
- package/dist/feed/index.cjs.map +1 -1
- package/dist/feed/index.d.cts +1 -1
- package/dist/feed/index.d.ts +1 -1
- package/dist/feed/index.mjs +2 -2
- package/dist/graph/index.cjs +97 -6
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.mjs +1 -1
- package/dist/index.cjs +111 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +4 -4
- package/dist/pipeline/index.cjs +111 -6
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.d.cts +1 -1
- package/dist/pipeline/index.d.ts +1 -1
- package/dist/pipeline/index.mjs +4 -4
- package/dist/schemas/index.cjs +9 -0
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +1 -1
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.mjs +1 -1
- package/package.json +9 -10
- package/dist/chunk-HILSUZOF.mjs.map +0 -1
- package/dist/chunk-PKUEOSZ3.mjs.map +0 -1
- package/dist/chunk-QJF4QCBJ.mjs.map +0 -1
- package/dist/curriculumFeedEmitter-6IK6PFDH.mjs +0 -4
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ export { i as ArchEdgeSchema, A as ArchNodeSchema, x as ArchitectureDetail, j as
|
|
|
2
2
|
export { b as Concept, d as ConceptCategory, c as ConceptCategorySchema, m as ConceptIntroduction, i as ConceptIntroductionSchema, C as ConceptSchema, l as DevelopmentPhase, D as DevelopmentPhaseSchema, j as HybridGraph, H as HybridGraphSchema, g as KnowledgeGraph, K as KnowledgeGraphSchema, f as LearningPathStep, L as LearningPathStepSchema, a as ProblemType, P as ProblemTypeSchema, k as ProjectConceptLink, h as ProjectConceptLinkSchema, e as SubjectInfo, S as SubjectInfoSchema } from './hybridGraphSchema-nrUeSwpU.cjs';
|
|
3
3
|
export { ExperimentProcedureSchema, GrammarRuleSchema, HardwareFeatureExtensionSchema, HardwareStepSchema, HardwareTaskExtensionSchema, HardwareTechStackExtensionSchema, LanguageConceptExtension, LanguageConceptExtensionSchema, MathConceptExtension, MathConceptExtensionSchema, MathTheoremSchema, ScienceConceptExtension, ScienceConceptExtensionSchema, ShapeSchema, ThreeDesignFeatureExtensionSchema, ThreeDesignTaskExtensionSchema, ThreeDesignTechStackExtensionSchema, WiringSchema } from './schemas/index.cjs';
|
|
4
4
|
export { a as DetectionConfidenceSchema, e as DomainCategory, D as DomainCategorySchema, c as DomainProfile, b as DomainProfileSchema, g as GraphType, G as GraphTypeSchema, d as InputType, I as InputTypeSchema, f as LearningMode, L as LearningModeSchema } from './domainProfileSchema-CwT3Ffsw.cjs';
|
|
5
|
-
export { g as CurriculumFeed, C as CurriculumFeedSchema, i as FeedEdge, c as FeedEdgeSchema, j as FeedGrouping, d as FeedGroupingSchema, F as FeedKeywordsSchema, h as FeedNode, b as FeedNodeSchema, f as FeedPhase, e as FeedPhaseSchema, a as FeedScaffoldCandidateSchema, v as validateCurriculumFeed } from './curriculumFeedSchema-
|
|
5
|
+
export { g as CurriculumFeed, C as CurriculumFeedSchema, i as FeedEdge, c as FeedEdgeSchema, j as FeedGrouping, d as FeedGroupingSchema, F as FeedKeywordsSchema, h as FeedNode, b as FeedNodeSchema, f as FeedPhase, e as FeedPhaseSchema, a as FeedScaffoldCandidateSchema, v as validateCurriculumFeed } from './curriculumFeedSchema-DUFwFyr2.cjs';
|
|
6
6
|
export { C as CppParseResult, P as PythonParseResult, S as SwiftParseResult, T as TsParseResult, f as mergeCppResults, d as mergePythonResults, m as mergeSwiftResults, b as mergeTsResults, e as parseCppFile, c as parsePythonFile, p as parseSwiftFile, a as parseTsFile } from './cpp-CZUPqJt9.cjs';
|
|
7
7
|
export { P as ParsedSyllabus, a as SyllabusTopic, S as SyllabusUnit, p as parseSyllabus } from './syllabusParser-MSX1fEzW.cjs';
|
|
8
8
|
export { K as Keyword, S as SourceContext, e as extractKeywords } from './keywordExtractor-BxlGRMHC.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { i as ArchEdgeSchema, A as ArchNodeSchema, x as ArchitectureDetail, j as
|
|
|
2
2
|
export { b as Concept, d as ConceptCategory, c as ConceptCategorySchema, m as ConceptIntroduction, i as ConceptIntroductionSchema, C as ConceptSchema, l as DevelopmentPhase, D as DevelopmentPhaseSchema, j as HybridGraph, H as HybridGraphSchema, g as KnowledgeGraph, K as KnowledgeGraphSchema, f as LearningPathStep, L as LearningPathStepSchema, a as ProblemType, P as ProblemTypeSchema, k as ProjectConceptLink, h as ProjectConceptLinkSchema, e as SubjectInfo, S as SubjectInfoSchema } from './hybridGraphSchema-nrUeSwpU.js';
|
|
3
3
|
export { ExperimentProcedureSchema, GrammarRuleSchema, HardwareFeatureExtensionSchema, HardwareStepSchema, HardwareTaskExtensionSchema, HardwareTechStackExtensionSchema, LanguageConceptExtension, LanguageConceptExtensionSchema, MathConceptExtension, MathConceptExtensionSchema, MathTheoremSchema, ScienceConceptExtension, ScienceConceptExtensionSchema, ShapeSchema, ThreeDesignFeatureExtensionSchema, ThreeDesignTaskExtensionSchema, ThreeDesignTechStackExtensionSchema, WiringSchema } from './schemas/index.js';
|
|
4
4
|
export { a as DetectionConfidenceSchema, e as DomainCategory, D as DomainCategorySchema, c as DomainProfile, b as DomainProfileSchema, g as GraphType, G as GraphTypeSchema, d as InputType, I as InputTypeSchema, f as LearningMode, L as LearningModeSchema } from './domainProfileSchema-CwT3Ffsw.js';
|
|
5
|
-
export { g as CurriculumFeed, C as CurriculumFeedSchema, i as FeedEdge, c as FeedEdgeSchema, j as FeedGrouping, d as FeedGroupingSchema, F as FeedKeywordsSchema, h as FeedNode, b as FeedNodeSchema, f as FeedPhase, e as FeedPhaseSchema, a as FeedScaffoldCandidateSchema, v as validateCurriculumFeed } from './curriculumFeedSchema-
|
|
5
|
+
export { g as CurriculumFeed, C as CurriculumFeedSchema, i as FeedEdge, c as FeedEdgeSchema, j as FeedGrouping, d as FeedGroupingSchema, F as FeedKeywordsSchema, h as FeedNode, b as FeedNodeSchema, f as FeedPhase, e as FeedPhaseSchema, a as FeedScaffoldCandidateSchema, v as validateCurriculumFeed } from './curriculumFeedSchema-DUFwFyr2.js';
|
|
6
6
|
export { C as CppParseResult, P as PythonParseResult, S as SwiftParseResult, T as TsParseResult, f as mergeCppResults, d as mergePythonResults, m as mergeSwiftResults, b as mergeTsResults, e as parseCppFile, c as parsePythonFile, p as parseSwiftFile, a as parseTsFile } from './cpp-CZUPqJt9.js';
|
|
7
7
|
export { P as ParsedSyllabus, a as SyllabusTopic, S as SyllabusUnit, p as parseSyllabus } from './syllabusParser-MSX1fEzW.js';
|
|
8
8
|
export { K as Keyword, S as SourceContext, e as extractKeywords } from './keywordExtractor-DU5XRN8-.js';
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import './chunk-R57WTNXW.mjs';
|
|
2
|
-
export { runDomainPipeline, runHybridGraphPipeline, runKnowledgeGraphPipeline, runProjectGraphPipeline } from './chunk-
|
|
3
|
-
export { emitCurriculumFeed } from './chunk-
|
|
2
|
+
export { runDomainPipeline, runHybridGraphPipeline, runKnowledgeGraphPipeline, runProjectGraphPipeline } from './chunk-G7HLFMD2.mjs';
|
|
3
|
+
export { emitCurriculumFeed } from './chunk-TWKIVUTQ.mjs';
|
|
4
4
|
export { ArchEdgeSchema, ArchNodeSchema, ArchitectureDetailSchema, CapabilitySchema, ConceptCategorySchema, ConceptIntroductionSchema, ConceptSchema, DataIntegrationSchema, DecompositionSchema, DetectionConfidenceSchema, DevelopmentPhaseSchema, DevelopmentStageSchema, DomainCategorySchema, DomainProfileSchema, ExperienceComponentSchema, ExperienceSchema, ExperimentProcedureSchema, FeatureSchema, GrammarRuleSchema, GraphTypeSchema, HardwareFeatureExtensionSchema, HardwareStepSchema, HardwareTaskExtensionSchema, HardwareTechStackExtensionSchema, HybridGraphSchema, ImplementationSchema, InputTypeSchema, JourneySchema, JourneyStepSchema, KnowledgeGraphSchema, LanguageConceptExtensionSchema, LearningModeSchema, LearningPathStepSchema, MathConceptExtensionSchema, MathTheoremSchema, MilestoneDecompositionSchema, MissingGapSchema, NavigationSchema, ProblemTypeSchema, ProductGoalSchema, ProductSchema, ProductUserSchema, ProjectConceptLinkSchema, ProjectGraphSchema, ProjectInfoSchema, RequirementSchema, ScienceConceptExtensionSchema, ScreenSchema, ShapeSchema, StepEffortSchema, StepOutcomeSchema, StepSchema, SubjectInfoSchema, TaskEffortSchema, TaskOutcomeSchema, TaskSchema, TechDebtSchema, TechStackSchema, ThreeDesignFeatureExtensionSchema, ThreeDesignTaskExtensionSchema, ThreeDesignTechStackExtensionSchema, UiStateSchema, WiringSchema } from './chunk-VCPIWJ7R.mjs';
|
|
5
|
-
export { CurriculumFeedSchema, FeedEdgeSchema, FeedGroupingSchema, FeedKeywordsSchema, FeedNodeSchema, FeedPhaseSchema, FeedScaffoldCandidateSchema, validateCurriculumFeed } from './chunk-
|
|
5
|
+
export { CurriculumFeedSchema, FeedEdgeSchema, FeedGroupingSchema, FeedKeywordsSchema, FeedNodeSchema, FeedPhaseSchema, FeedScaffoldCandidateSchema, validateCurriculumFeed } from './chunk-E4GCCWJO.mjs';
|
|
6
6
|
import './chunk-IJZUV7N3.mjs';
|
|
7
7
|
export { mergeCppResults, mergePythonResults, mergeSwiftResults, mergeTsResults, parseCppFile, parsePythonFile, parseSwiftFile, parseTsFile } from './chunk-DRVOV5ZD.mjs';
|
|
8
8
|
export { scoreByContent, scoreByPath, scoreFiles, selectRelevantFiles } from './chunk-RKRNOVKO.mjs';
|
|
@@ -10,7 +10,7 @@ export { extractKeywords } from './chunk-XMHKWHVK.mjs';
|
|
|
10
10
|
import './chunk-7XGWW6CB.mjs';
|
|
11
11
|
export { detectDomain, detectDomainProfile, detectInputType, detectLearningMode } from './chunk-BL5NBKPH.mjs';
|
|
12
12
|
import './chunk-ZKLT27T4.mjs';
|
|
13
|
-
export { CIO_CODE_RE, CONCEPT_CODE_RE, LEARNER_CLAUSE, SIO_CODE_RE, ULO_CODE_RE, assignConceptCodes, auditDepthLayers, auditPhasePlan, auditSyllabusCoverage, breakPrerequisiteCycles, cioActionSlug, cioCode, conceptCodeFromName, detectPrerequisiteCycles, escalateAndMapConcepts, extractFeatureSteps, extractFeatureStepsBatched, extractProjectOverview, extractScaffold, generateHybridGraph, generateKnowledgeGraph, sioCode, standardStatement, techTagFor, uloCode, verifyKnowledgeGraph, verifyProjectGraph } from './chunk-
|
|
13
|
+
export { CIO_CODE_RE, CONCEPT_CODE_RE, LEARNER_CLAUSE, SIO_CODE_RE, ULO_CODE_RE, assignConceptCodes, auditDepthLayers, auditPhasePlan, auditSyllabusCoverage, breakPrerequisiteCycles, cioActionSlug, cioCode, conceptCodeFromName, detectPrerequisiteCycles, escalateAndMapConcepts, extractFeatureSteps, extractFeatureStepsBatched, extractProjectOverview, extractScaffold, generateHybridGraph, generateKnowledgeGraph, sioCode, standardStatement, techTagFor, uloCode, verifyKnowledgeGraph, verifyProjectGraph } from './chunk-TYXSJUQU.mjs';
|
|
14
14
|
export { parseSyllabus } from './chunk-T4Y2DE2W.mjs';
|
|
15
15
|
import './chunk-KMYENICQ.mjs';
|
|
16
16
|
export { resolveConcepts } from './chunk-KNDBODUQ.mjs';
|
package/dist/pipeline/index.cjs
CHANGED
|
@@ -109,6 +109,15 @@ var init_curriculumFeedSchema = __esm({
|
|
|
109
109
|
reason: zod.z.string().default("")
|
|
110
110
|
})).optional(),
|
|
111
111
|
is_core: zod.z.boolean().default(false),
|
|
112
|
+
// Depth layer text (optional, additive — old feeds validate unchanged).
|
|
113
|
+
// Carries the ULO/CIO/SIO authored text from the KnowledgeGraph concept
|
|
114
|
+
// so downstream consumers (KX generator) can inject depth-appropriate
|
|
115
|
+
// material into their prompts without a second LLM call.
|
|
116
|
+
depth_context: zod.z.object({
|
|
117
|
+
ulo: zod.z.string().default(""),
|
|
118
|
+
cio: zod.z.string().default(""),
|
|
119
|
+
sio: zod.z.array(zod.z.string()).default([])
|
|
120
|
+
}).optional(),
|
|
112
121
|
// Progressive-completion bookkeeping (feed v2, additive):
|
|
113
122
|
// phase_id = development phase that introduces/uses this node;
|
|
114
123
|
// introduce_aspect = how the phase teaches a concept node (first intro, advanced
|
|
@@ -262,6 +271,11 @@ function feedNodeFromConcept(concept) {
|
|
|
262
271
|
// concepts are taught, not shipped — checkpoints live on product steps
|
|
263
272
|
...deriveDepthInputs(Math.max(0, Math.round(num(concept.estimated_minutes, 15))), deriveConceptDepthHint(concept)),
|
|
264
273
|
is_core: false,
|
|
274
|
+
depth_context: {
|
|
275
|
+
ulo: str(concept.ulo),
|
|
276
|
+
cio: str(concept.cio),
|
|
277
|
+
sio: strs(concept.sio)
|
|
278
|
+
},
|
|
265
279
|
phase_id: "",
|
|
266
280
|
introduce_aspect: null
|
|
267
281
|
};
|
|
@@ -3894,7 +3908,42 @@ async function generateKnowledgeGraph(options) {
|
|
|
3894
3908
|
const structuredTopicsGuide = parsedSyllabus && parsedSyllabus.allTopics.length > 0 ? `
|
|
3895
3909
|
STRUCTURED SYLLABUS TOPICS (Every topic MUST map to at least one concept to ensure 100% syllabus coverage):
|
|
3896
3910
|
` + parsedSyllabus.allTopics.map((t) => `- [${t.unitTitle}] ${t.id}: ${t.title} (Keywords: ${t.keywords.join(", ")})`).join("\n") + "\n" : "";
|
|
3897
|
-
const systemPrompt =
|
|
3911
|
+
const systemPrompt = `You are an expert curriculum designer. Decompose the given subject into a structured knowledge graph with concepts, prerequisites, and problem types.
|
|
3912
|
+
|
|
3913
|
+
CRITICAL RULES:
|
|
3914
|
+
1. Each concept MUST have the three depth layers, authored against this CONTRACT:
|
|
3915
|
+
- ulo (WHAT + WHY): bound to the CONCEPT's intrinsic NATURE. It explains what the
|
|
3916
|
+
concept is and why it exists \u2014 the problem it solves in principle. It must be
|
|
3917
|
+
TECHNOLOGY-AGNOSTIC: never name a concrete library, API, function, file format,
|
|
3918
|
+
tool or language feature. Typical assessment level: Remember / Understand.
|
|
3919
|
+
- cio (HOW): the MECHANISM \u2014 how the concept works and solves that problem, step
|
|
3920
|
+
by step. Still bound to the concept's nature: more concrete than the ULO, but
|
|
3921
|
+
NOT tied to one specific technology (no concrete API names). CIO capability is
|
|
3922
|
+
assessed INDIRECTLY, through completing contextual work, not in isolation.
|
|
3923
|
+
- sio (IMPLEMENTATION): an array of 2-4 items. EVERY item MUST reference concrete
|
|
3924
|
+
KEYWORDS/technologies (a real API, function, module, file, or named pattern) and
|
|
3925
|
+
describe a completable, context-specific implementation task. Application,
|
|
3926
|
+
Analysis and Creation skills are assessed INDIRECTLY through completing these
|
|
3927
|
+
items. There is NO fixed Bloom ceiling for a layer \u2014 but concreteness MUST
|
|
3928
|
+
strictly increase: SIO more technology-bound than CIO, CIO more concrete than ULO.
|
|
3929
|
+
- prerequisites: concept IDs that must be learned first (MUST NOT create cycles)
|
|
3930
|
+
- problem_types: 2-4 problem types with bloom_level and difficulty. Remember and
|
|
3931
|
+
Understand problem types test the ULO/CIO directly; Apply-and-above types are
|
|
3932
|
+
proxies for SIO completion in context.
|
|
3933
|
+
- techniques: methods, formulas, tools
|
|
3934
|
+
2. Prerequisite chains MUST be acyclic (no concept can depend on itself or create a loop)
|
|
3935
|
+
3. Concepts should be ordered by prerequisite dependency (topological sort)
|
|
3936
|
+
4. Problem types should range from Remember to Apply (not all at same level)
|
|
3937
|
+
5. Group concepts into categories (chapters/sections)
|
|
3938
|
+
6. ALL text in ENGLISH (even if input is Vietnamese)
|
|
3939
|
+
7. NEVER invent concepts not present in the syllabus
|
|
3940
|
+
8. KEYWORDS: Each concept MUST include 5-10 domain-specific keywords that:
|
|
3941
|
+
- Are concrete terms a student encounters when studying THIS concept
|
|
3942
|
+
- Include at least 2 technology-specific terms (APIs, functions, types, tools)
|
|
3943
|
+
- Are DISTINCT from keywords of other concepts (minimal overlap)
|
|
3944
|
+
- NEVER generic English words (e.g. "view", "data", "code" are TOO generic)
|
|
3945
|
+
- Example for "SwiftUI Layout": ["VStack", "HStack", "ZStack", ".padding()", ".frame()", "alignment", "Spacer", "LazyVGrid"]
|
|
3946
|
+
9. Return JSON matching the KnowledgeGraphSchema`;
|
|
3898
3947
|
const userPrompt = `Subject: ${subject}
|
|
3899
3948
|
${description ? `Description: ${description}` : ""}
|
|
3900
3949
|
${structuredTopicsGuide}${truncatedSyllabus ? `Syllabus:
|
|
@@ -3915,8 +3964,9 @@ Return JSON:
|
|
|
3915
3964
|
{
|
|
3916
3965
|
"id": "C1",
|
|
3917
3966
|
"name": "Concept name",
|
|
3918
|
-
"description": "
|
|
3967
|
+
"description": "2-3 sentence description: what this concept covers, why a learner encounters it, and what mastering it enables. Must be specific enough that a student reading only this description understands the concept's scope.",
|
|
3919
3968
|
"category": "category_id",
|
|
3969
|
+
"keywords": ["specific_term_1", "concrete_api_2", "method_call_3", "tool_or_type_4", "syntax_keyword_5", "concept_term_6"],
|
|
3920
3970
|
"ulo": "WHAT + WHY in technology-agnostic language: what the concept is and the problem it exists to solve. No library/API/tool names.",
|
|
3921
3971
|
"cio": "HOW the mechanism works, still technology-agnostic but more concrete than the ULO.",
|
|
3922
3972
|
"sio": ["Concrete task naming a REAL API/function/module/file from the target technology, completable end to end", "Another technology-bound task using a different concrete keyword"],
|
|
@@ -3957,18 +4007,23 @@ Return JSON:
|
|
|
3957
4007
|
log("STEP_2", "Validating and cleaning knowledge graph...");
|
|
3958
4008
|
const concepts = result.concepts || [];
|
|
3959
4009
|
const categories = result.categories || [];
|
|
4010
|
+
for (const c of concepts) {
|
|
4011
|
+
if ((c.description || "").length < 50) {
|
|
4012
|
+
warnings.push("Concept " + c.id + ": description too short (" + (c.description || "").length + " chars) \u2014 may produce shallow KX narratives");
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
3960
4015
|
{
|
|
3961
4016
|
const STOP = /* @__PURE__ */ new Set(["and", "the", "for", "with", "from", "that", "this", "into", "when", "while", "using", "their", "your", "each", "how", "why", "what", "between", "through", "about"]);
|
|
3962
4017
|
const tokensFrom = (text) => text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length >= 4 && !STOP.has(w));
|
|
3963
4018
|
for (const c of concepts) {
|
|
3964
4019
|
const existing = (c.keywords || []).map((k) => String(k).trim()).filter(Boolean);
|
|
3965
4020
|
if (existing.length === 0) {
|
|
3966
|
-
const derived = [.../* @__PURE__ */ new Set([...tokensFrom(c.name), ...tokensFrom(c.description || "")])].slice(0,
|
|
4021
|
+
const derived = [.../* @__PURE__ */ new Set([...tokensFrom(c.name), ...tokensFrom(c.description || "")])].slice(0, 8);
|
|
3967
4022
|
if (derived.length === 0) {
|
|
3968
4023
|
throw new Error("Concept " + c.id + " (" + c.name + ") has no keywords and none could be derived from name/description \u2014 fail-closed");
|
|
3969
4024
|
}
|
|
3970
4025
|
c.keywords = derived;
|
|
3971
|
-
warnings.push("Concept " + c.id + ": empty keyword set - derived " + derived.join(", ") + " from name/description");
|
|
4026
|
+
warnings.push("Concept " + c.id + ": empty keyword set - derived " + derived.join(", ") + " from name/description (WARNING: LLM returned no keywords)");
|
|
3972
4027
|
} else {
|
|
3973
4028
|
c.keywords = existing;
|
|
3974
4029
|
}
|
|
@@ -4093,6 +4148,52 @@ Return JSON:
|
|
|
4093
4148
|
}
|
|
4094
4149
|
log("STEP_5", "Depth layers authored: " + concepts.length + " concepts, audit " + lo.audits.filter((a) => a.passed).length + "/" + concepts.length + " passed");
|
|
4095
4150
|
}
|
|
4151
|
+
{
|
|
4152
|
+
for (const concept of concepts) {
|
|
4153
|
+
const sioText = (concept.sio || []).join(" ");
|
|
4154
|
+
const techTokens = [];
|
|
4155
|
+
let m;
|
|
4156
|
+
const techTokenRe = /`([^`]+)`/g;
|
|
4157
|
+
while ((m = techTokenRe.exec(sioText)) !== null) {
|
|
4158
|
+
if (m[1].length >= 3 && m[1].length <= 40) techTokens.push(m[1]);
|
|
4159
|
+
}
|
|
4160
|
+
const annotationRe = /(?:^|[\s(])(@[A-Za-z]\w*)/g;
|
|
4161
|
+
while ((m = annotationRe.exec(sioText)) !== null) techTokens.push(m[1]);
|
|
4162
|
+
const dotRe = /\b\w+\.\w+\(/g;
|
|
4163
|
+
while ((m = dotRe.exec(sioText)) !== null) techTokens.push(m[0].replace("(", ""));
|
|
4164
|
+
const modifierRe = /(?:^|[\s(])(\.[a-z]\w*)\b/g;
|
|
4165
|
+
while ((m = modifierRe.exec(sioText)) !== null) techTokens.push(m[1]);
|
|
4166
|
+
const camelRe = /\b[a-z]+[A-Z][A-Za-z]+\b/g;
|
|
4167
|
+
while ((m = camelRe.exec(sioText)) !== null) techTokens.push(m[0]);
|
|
4168
|
+
const existing = new Set((concept.keywords || []).map((k) => k.toLowerCase()));
|
|
4169
|
+
const newTokens = [...new Set(techTokens)].filter((t) => !existing.has(t.toLowerCase())).slice(0, 8);
|
|
4170
|
+
if (newTokens.length > 0) {
|
|
4171
|
+
concept.keywords = [...concept.keywords || [], ...newTokens];
|
|
4172
|
+
warnings.push("Concept " + concept.id + ": enriched keywords with " + newTokens.length + " SIO-derived tokens");
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
log("STEP_5b", "SIO-keyword enrichment complete");
|
|
4176
|
+
}
|
|
4177
|
+
{
|
|
4178
|
+
for (const concept of concepts) {
|
|
4179
|
+
const sioCount = (concept.sio || []).length;
|
|
4180
|
+
const ptCount = (concept.problem_types || []).length;
|
|
4181
|
+
const prereqCount = (concept.prerequisites || []).length;
|
|
4182
|
+
const hasHighBloom = (concept.problem_types || []).some(
|
|
4183
|
+
(pt) => ["Analyze", "Evaluate", "Create"].includes(pt.bloom_level || "")
|
|
4184
|
+
);
|
|
4185
|
+
const score = Math.min(1, sioCount * 0.2 + ptCount * 0.15 + prereqCount * 0.15 + (hasHighBloom ? 0.2 : 0));
|
|
4186
|
+
const calibrated = Math.round(15 + score * 45);
|
|
4187
|
+
const llmEstimate = concept.estimated_minutes || 30;
|
|
4188
|
+
if (llmEstimate === 30 || Math.abs(calibrated - llmEstimate) / llmEstimate > 0.5) {
|
|
4189
|
+
concept.estimated_minutes = calibrated;
|
|
4190
|
+
if (llmEstimate !== calibrated) {
|
|
4191
|
+
warnings.push("Concept " + concept.id + ": minutes calibrated " + llmEstimate + "m \u2192 " + calibrated + "m (score=" + score.toFixed(2) + ")");
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
log("STEP_5c", "Minute calibration complete");
|
|
4196
|
+
}
|
|
4096
4197
|
for (const step of learningPath) {
|
|
4097
4198
|
if (!conceptIds.has(step.concept_id)) {
|
|
4098
4199
|
warnings.push(`Learning path references non-existent concept ${step.concept_id}`);
|
|
@@ -4391,8 +4492,12 @@ async function decomposePhases(args) {
|
|
|
4391
4492
|
const linkList = links.map(
|
|
4392
4493
|
(l) => "- " + l.feature_id + " -> " + l.concept_id + " (" + l.depth + ")"
|
|
4393
4494
|
).join("\n") || "(none)";
|
|
4394
|
-
const systemPrompt = 'You decompose a software project build into PROGRESSIVE COMPLETION PHASES for learning purposes.\n\nA phase is NOT a feature and NOT a milestone list: it is a cross-feature slice of the\nproduct whose completion yields a DEMONSTRABLY more complete product. Build up gradually:\nthe product grows feature by feature across phases, and each phase adds its features to\nwhat previous phases already built.\n\nRULES:\n1. Every feature must be assigned to EXACTLY ONE phase (no feature reused, none skipped).\n2. Phases are ordered; later phases depend on earlier ones and yield a more complete product.\n3. product_completion describes concretely what the product can DO once the phase is done.\n4. introduces lists which concepts the phase must teach BEFORE its feature work starts:\n - aspect new: first time the concept appears in the course\n - aspect advanced: a concept introduced in an EARLIER phase, revisited here at a\n higher depth (an advanced aspect of the same concept, e.g. validation rules on top\n of basic data modeling). Use the note field to say which aspect.\n - aspect preview: a light awareness pass ("know it exists", ULO depth only, ~5 min)\n placed in an EARLIER phase when its feature work needs the vocabulary before the\n full teach. The anchor phase still owns the full new introduction.\n5. A concept MUST be introduced (new) no later than the first phase that consumes it.\n6. A concept must not be introduced before its own prerequisites are introduced.\n7. Typically 3-6 phases for a small project; keep phases balanced.\n8. Phase 1 usually covers project setup/foundation features plus the first minimal slice.\
|
|
4395
|
-
const
|
|
4495
|
+
const systemPrompt = 'You decompose a software project build into PROGRESSIVE COMPLETION PHASES for learning purposes.\n\nA phase is NOT a feature and NOT a milestone list: it is a cross-feature slice of the\nproduct whose completion yields a DEMONSTRABLY more complete product. Build up gradually:\nthe product grows feature by feature across phases, and each phase adds its features to\nwhat previous phases already built.\n\nRULES:\n1. Every feature must be assigned to EXACTLY ONE phase (no feature reused, none skipped).\n2. Phases are ordered; later phases depend on earlier ones and yield a more complete product.\n3. product_completion describes concretely what the product can DO once the phase is done.\n4. introduces lists which concepts the phase must teach BEFORE its feature work starts:\n - aspect new: first time the concept appears in the course\n - aspect advanced: a concept introduced in an EARLIER phase, revisited here at a\n higher depth (an advanced aspect of the same concept, e.g. validation rules on top\n of basic data modeling). Use the note field to say which aspect.\n - aspect preview: a light awareness pass ("know it exists", ULO depth only, ~5 min)\n placed in an EARLIER phase when its feature work needs the vocabulary before the\n full teach. The anchor phase still owns the full new introduction.\n5. A concept MUST be introduced (new) no later than the first phase that consumes it.\n6. A concept must not be introduced before its own prerequisites are introduced.\n7. Typically 3-6 phases for a small project; keep phases balanced.\n8. MINUTE BALANCE: Each phase should contain approximately 120-240 total minutes of\n concept + feature work (about 3-5 sessions of 90 minutes each). If a phase\n would contain < 60 minutes (too thin) or > 400 minutes (too heavy), rebalance.\n9. Phase 1 usually covers project setup/foundation features plus the first minimal slice.\n10. Return JSON only.';
|
|
4496
|
+
const totalFeatureMinutes = features.reduce((s, f) => s + (f.steps || []).reduce((ss, st) => ss + (st.effort?.estimated_minutes || 15), 0), 0);
|
|
4497
|
+
const totalConceptMinutes = concepts.reduce((s, c) => s + (c.estimated_minutes || 30), 0);
|
|
4498
|
+
const totalMinutes = totalFeatureMinutes + totalConceptMinutes;
|
|
4499
|
+
const targetPhaseCount = Math.max(3, Math.round(totalMinutes / 180));
|
|
4500
|
+
const baseUserPrompt = "FEATURES:\n" + featureList + "\n\nCONCEPTS:\n" + conceptList + "\n\nFEATURE-CONCEPT LINKS:\n" + linkList + "\n\nTOTAL MINUTES: ~" + totalMinutes + "m (" + totalFeatureMinutes + "m features + " + totalConceptMinutes + "m concepts)\nTARGET: ~" + targetPhaseCount + " phases of ~180m each\n\nReturn JSON with a phases array. Each phase: { id: PH1, name, product_completion, feature_ids: [F0, F1], introduces: [{ concept_id: C1, aspect: new or advanced, note }] }.\n";
|
|
4396
4501
|
const MAX_DECOMPOSE_ATTEMPTS = 3;
|
|
4397
4502
|
let auditErrors = [];
|
|
4398
4503
|
let phases = [];
|