@thanh01.pmt/domain-kit 0.2.1 → 0.4.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/README.md +42 -11
- package/dist/{chunk-CRN6D4HG.mjs → chunk-HILSUZOF.mjs} +32 -8
- package/dist/chunk-HILSUZOF.mjs.map +1 -0
- package/dist/{chunk-23TQPTHG.mjs → chunk-LZQLLAYP.mjs} +5 -5
- package/dist/{chunk-23TQPTHG.mjs.map → chunk-LZQLLAYP.mjs.map} +1 -1
- package/dist/{chunk-HH4UX65C.mjs → chunk-PKUEOSZ3.mjs} +42 -4
- package/dist/chunk-PKUEOSZ3.mjs.map +1 -0
- package/dist/{chunk-HUDFN4IX.mjs → chunk-QJF4QCBJ.mjs} +99 -4
- package/dist/chunk-QJF4QCBJ.mjs.map +1 -0
- package/dist/{chunk-WHBAGJWN.mjs → chunk-VCPIWJ7R.mjs} +4 -4
- package/dist/chunk-VCPIWJ7R.mjs.map +1 -0
- package/dist/curriculumFeedEmitter-6IK6PFDH.mjs +4 -0
- package/dist/{curriculumFeedEmitter-E5DAJYUZ.mjs.map → curriculumFeedEmitter-6IK6PFDH.mjs.map} +1 -1
- package/dist/{curriculumFeedSchema-TEeQg2bY.d.ts → curriculumFeedSchema-B66H3gEV.d.cts} +148 -8
- package/dist/{curriculumFeedSchema-TEeQg2bY.d.cts → curriculumFeedSchema-B66H3gEV.d.ts} +148 -8
- package/dist/feed/index.cjs +136 -3
- 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 +30 -5
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +2 -2
- package/dist/graph/index.d.ts +2 -2
- package/dist/graph/index.mjs +1 -1
- package/dist/{hybridGraphPipeline-DVZYLCAQ.d.ts → hybridGraphPipeline-DXQDbBEj.d.ts} +14 -2
- package/dist/{hybridGraphPipeline-DmWRKYXf.d.cts → hybridGraphPipeline-dT-bio-3.d.cts} +14 -2
- package/dist/{hybridGraphSchema-BCgXicgA.d.ts → hybridGraphSchema-nrUeSwpU.d.cts} +15 -15
- package/dist/{hybridGraphSchema-BCgXicgA.d.cts → hybridGraphSchema-nrUeSwpU.d.ts} +15 -15
- package/dist/index.cjs +168 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +5 -5
- package/dist/pipeline/index.cjs +165 -8
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.d.cts +3 -3
- package/dist/pipeline/index.d.ts +3 -3
- package/dist/pipeline/index.mjs +4 -4
- package/dist/schemas/index.cjs +42 -4
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +2 -2
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/index.mjs +2 -2
- package/package.json +10 -9
- package/LICENSE +0 -21
- package/dist/chunk-CRN6D4HG.mjs.map +0 -1
- package/dist/chunk-HH4UX65C.mjs.map +0 -1
- package/dist/chunk-HUDFN4IX.mjs.map +0 -1
- package/dist/chunk-WHBAGJWN.mjs.map +0 -1
- package/dist/curriculumFeedEmitter-E5DAJYUZ.mjs +0 -4
package/README.md
CHANGED
|
@@ -151,7 +151,8 @@ const feed = emitCurriculumFeed(result.projectGraph); // or knowledgeGraph or h
|
|
|
151
151
|
console.log(feed.learning_nodes.length); // unified nodes ready for planner
|
|
152
152
|
console.log(feed.dependency_edges.length); // knowledge + task edges
|
|
153
153
|
console.log(feed.suggested_groupings); // feature/category groupings
|
|
154
|
-
//
|
|
154
|
+
console.log(feed.phases.length); // non-empty ⇒ learning_nodes are in teaching order (phases define units)
|
|
155
|
+
// Each node has: bloom_hint, depth_hint, keywords.new/.prerequisite, introduce_aspect, user_visible_deliverable
|
|
155
156
|
```
|
|
156
157
|
|
|
157
158
|
---
|
|
@@ -399,10 +400,11 @@ All schemas are Zod-validated TypeScript types.
|
|
|
399
400
|
| `DomainProfileSchema` | `domainProfileSchema.ts` | Domain detection output |
|
|
400
401
|
| `HardwareFeatureExtension` | `domainExtensions.ts` | Hardware overlay (wiring, materials) |
|
|
401
402
|
| `ThreeDesignFeatureExtension` | `domainExtensions.ts` | 3D Design overlay (shapes, dimensions) |
|
|
402
|
-
| `CurriculumFeedSchema` | `curriculumFeedSchema.ts` | Planner-ready normalized feed (nodes, edges, groupings) |
|
|
403
|
+
| `CurriculumFeedSchema` | `curriculumFeedSchema.ts` | Planner-ready normalized feed (nodes, edges, groupings, phases) |
|
|
403
404
|
| `FeedNodeSchema` | `curriculumFeedSchema.ts` | Individual learning node (concept, skill, or product step) |
|
|
404
405
|
| `FeedEdgeSchema` | `curriculumFeedSchema.ts` | Dependency edge (knowledge or task) |
|
|
405
406
|
| `FeedGroupingSchema` | `curriculumFeedSchema.ts` | Suggested grouping of nodes (feature or category) |
|
|
407
|
+
| `FeedPhaseSchema` | `curriculumFeedSchema.ts` | Development phase — when non-empty, defines teaching sequence and unit structure |
|
|
406
408
|
|
|
407
409
|
### Key Types
|
|
408
410
|
|
|
@@ -486,9 +488,10 @@ type AssembledRoadmap = {
|
|
|
486
488
|
type CurriculumFeed = {
|
|
487
489
|
schema_version: 2;
|
|
488
490
|
source: { graph_type: 'project_graph' | 'knowledge_graph' | 'hybrid_graph'; warnings: string[]; hallucination_count: number };
|
|
489
|
-
learning_nodes: FeedNode[];
|
|
491
|
+
learning_nodes: FeedNode[]; // in TEACHING ORDER when phases[] is non-empty
|
|
490
492
|
dependency_edges: FeedEdge[];
|
|
491
493
|
suggested_groupings: FeedGrouping[];
|
|
494
|
+
phases: FeedPhase[]; // when non-empty, THESE — not suggested_groupings — define the teaching sequence and unit structure
|
|
492
495
|
}
|
|
493
496
|
|
|
494
497
|
type FeedNode = {
|
|
@@ -505,6 +508,20 @@ type FeedNode = {
|
|
|
505
508
|
references: { file: string; evidence: string }[];
|
|
506
509
|
feature_id: string | null;
|
|
507
510
|
concept_ref: string | null;
|
|
511
|
+
phase_id: string; // development phase that introduces/uses this node ('' on legacy feeds)
|
|
512
|
+
introduce_aspect: 'new' | 'advanced' | 'preview' | null; // first intro / advanced revisit / preview priming
|
|
513
|
+
user_visible_deliverable: string; // step's outcome.user_visible — checkpoint candidate for session cutting ('' on concept nodes)
|
|
514
|
+
depth_variants?: { ulo: number; cio: number; sio: number }; // minutes per depth level — reconciler price list (ULO ≤ CIO ≤ SIO)
|
|
515
|
+
depth_scaffold_candidates?: { from_depth: 'ulo' | 'cio' | 'sio'; to_depth: 'ulo' | 'cio' | 'sio'; minutes_saved: number; reason: string }[]; // DEPTH downgrades (SIO→CIO, CIO→ULO) — parallel to scaffold_candidates
|
|
516
|
+
is_core: boolean; // Master-Tree core concept — never depth-downgraded; escalate instead
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
type FeedPhase = {
|
|
520
|
+
id: string;
|
|
521
|
+
order: number; // 1-based teaching order
|
|
522
|
+
name: string;
|
|
523
|
+
product_completion: string;
|
|
524
|
+
node_ids: string[]; // nodes of this phase, already in teaching order
|
|
508
525
|
}
|
|
509
526
|
|
|
510
527
|
type FeedEdge = {
|
|
@@ -640,19 +657,26 @@ const feed = emitCurriculumFeed(graph, {
|
|
|
640
657
|
});
|
|
641
658
|
|
|
642
659
|
// Returns CurriculumFeed with:
|
|
643
|
-
// - learning_nodes[] — unified node format (concept | skill | product_step)
|
|
660
|
+
// - learning_nodes[] — unified node format (concept | skill | product_step), in teaching order when phases[] is non-empty
|
|
644
661
|
// - dependency_edges[] — knowledge (prerequisite) or task (build order) edges
|
|
645
|
-
// - suggested_groupings[] — feature or category groupings
|
|
646
|
-
// -
|
|
662
|
+
// - suggested_groupings[] — feature or category groupings (layout hint only)
|
|
663
|
+
// - phases[] — development phases; when non-empty, the teaching sequence + unit structure
|
|
664
|
+
// - Each node has: bloom_hint, depth_hint (ulo/cio/sio), keywords.new vs .prerequisite,
|
|
665
|
+
// introduce_aspect (new/advanced/preview), user_visible_deliverable,
|
|
666
|
+
// depth_variants + depth_scaffold_candidates + is_core (depth-reconcile inputs)
|
|
647
667
|
```
|
|
648
668
|
|
|
649
669
|
**Key behaviors:**
|
|
650
|
-
- **
|
|
670
|
+
- **Teaching-order emission (contract, 2026-09-18):** when a hybrid graph carries `phases[]`, the `nodes` array follows the **phase teaching sequence** — the order in the file IS the order in the classroom. The former "concepts emitted first, then steps" array layout is ABOLISHED: it contradicted phase order, fabricated backwards prerequisite edges, and caused the planner's "Teaching-order violation" failure (see postmortem 2026-09-17 §9)
|
|
671
|
+
- **No fabricated backwards edges:** when a keyword consumer sits in an EARLIER phase than the concept's anchor teach (and no preview covers it), the emitter does NOT invent a dependency edge — it records a drift **warning** instead (`hybrid link drift: …`); the host decides, the emitter reports
|
|
672
|
+
- **Overtake guard:** a product step must never become the introducer of a concept's vocabulary; the first appearance of a keyword belongs to the concept (or its preview node) that teaches it
|
|
673
|
+
- **Preview priming (aspect `preview`, kit ≥0.3.0):** a phase may declare a light awareness pass for a concept whose anchor teach lives in a LATER phase — emitted as node `<cid>__PREVxx` with depth `ulo`, bloom `Understand`, ~25% minutes (min 5), `keywords.all` (making it the legitimate vocabulary introducer), no prerequisite edges, no scaffolding. Five fail-closed emission rules: unknown concept, already-introduced concept, duplicate preview, no anchor anywhere, anchor not in a later phase
|
|
651
674
|
- **Knowledge graphs**: concepts + prerequisite edges + category groupings
|
|
652
675
|
- **Project graphs**: features → steps + depends_on edges + feature groupings
|
|
653
676
|
- **Pass-through**: if input already has `learning_nodes[]`, validates and returns as-is
|
|
654
677
|
- **Legacy rejection**: throws descriptive error if graph has `implementation.tasks` but no `features[].steps` (old knowledge-tree format)
|
|
655
|
-
- **New/prerequisite keywords**: computed in
|
|
678
|
+
- **New/prerequisite keywords**: computed in **teaching order** (phase sequence when phases exist, array order otherwise) — first appearance = new, seen before = prerequisite. Anchoring keywords to array position instead of teaching order is the exact assumption that caused the 2026-09-17 incident
|
|
679
|
+
- **Fail-closed validation**: output is validated before return — duplicate IDs, unresolvable edges, self-loops, non-empty, **and the teaching-order invariant**: when phases define the sequence, a prerequisite must live in the same or an EARLIER phase than its consumer (a violation throws at emission, never defers to the planner)
|
|
656
680
|
|
|
657
681
|
### Parsers
|
|
658
682
|
|
|
@@ -723,8 +747,15 @@ STEP 9: Feed Emission
|
|
|
723
747
|
→ Convert project_graph → FeedNode[] (kind: product_step) + FeatureGroupings
|
|
724
748
|
→ Convert knowledge_graph → FeedNode[] (kind: concept) + CategoryGroupings
|
|
725
749
|
→ Convert hybrid_graph → combined nodes + knowledge/task edges + hybrid link depth hints
|
|
726
|
-
→
|
|
727
|
-
→
|
|
750
|
+
→ Project steps: project outcome.user_visible onto user_visible_deliverable (checkpoint candidate)
|
|
751
|
+
→ Concept nodes: emit depth_variants (ULO ≤ CIO ≤ SIO minutes) + depth_scaffold_candidates + is_core
|
|
752
|
+
→ Teaching order: when phases[] exist, nodes are emitted in phase sequence; new/prerequisite
|
|
753
|
+
keywords computed in TEACHING order (first appearance = new), never array position
|
|
754
|
+
→ Preview priming: phase-declared __PREVxx awareness nodes carry keywords.all (legitimate
|
|
755
|
+
vocabulary introducer) without fabricating prerequisite edges
|
|
756
|
+
→ Validate: fail-closed (duplicate IDs, edge resolution, self-loops, non-empty, duplicate
|
|
757
|
+
phase ids, and the teaching-order invariant: a prerequisite must live in the same or an
|
|
758
|
+
EARLIER phase than its consumer — a backwards edge throws at emission, never in the planner)
|
|
728
759
|
```
|
|
729
760
|
|
|
730
761
|
### Knowledge Graph Pipeline (Concept-Driven)
|
|
@@ -949,7 +980,7 @@ import {
|
|
|
949
980
|
ProjectGraphSchema, KnowledgeGraphSchema, HybridGraphSchema,
|
|
950
981
|
DomainProfileSchema, ConceptMappingSchema, AssembledRoadmapSchema,
|
|
951
982
|
KnowledgeConceptSchema, KnowledgeLearningPathStepSchema,
|
|
952
|
-
CurriculumFeedSchema, FeedNodeSchema, FeedEdgeSchema, FeedGroupingSchema,
|
|
983
|
+
CurriculumFeedSchema, FeedNodeSchema, FeedEdgeSchema, FeedGroupingSchema, FeedPhaseSchema,
|
|
953
984
|
} from '@thanh01.pmt/domain-kit';
|
|
954
985
|
|
|
955
986
|
// Roadmap assembly
|
|
@@ -2120,6 +2120,8 @@ function auditPhasePlan(plan, features, concepts, links, warnings, log) {
|
|
|
2120
2120
|
const phases = [];
|
|
2121
2121
|
const featurePhase = /* @__PURE__ */ new Map();
|
|
2122
2122
|
const newIntroPhase = /* @__PURE__ */ new Map();
|
|
2123
|
+
const previewsSeen = /* @__PURE__ */ new Set();
|
|
2124
|
+
const previewPhase = /* @__PURE__ */ new Map();
|
|
2123
2125
|
const errors = [];
|
|
2124
2126
|
plan.forEach((rp, idx) => {
|
|
2125
2127
|
const id = String(rp.id || "PH" + (idx + 1));
|
|
@@ -2151,7 +2153,22 @@ function auditPhasePlan(plan, features, concepts, links, warnings, log) {
|
|
|
2151
2153
|
errors.push("Phase " + id + ": introduces unknown concept " + cid);
|
|
2152
2154
|
continue;
|
|
2153
2155
|
}
|
|
2154
|
-
const
|
|
2156
|
+
const rawAspect = String(ri.aspect || "new");
|
|
2157
|
+
const aspect = rawAspect === "advanced" || rawAspect === "preview" ? rawAspect : "new";
|
|
2158
|
+
if (aspect === "preview") {
|
|
2159
|
+
if (newIntroPhase.has(cid)) {
|
|
2160
|
+
errors.push("Phase " + id + ": preview of " + cid + " after its new introduction in phase " + newIntroPhase.get(cid) + " - preview must precede the anchor teach");
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
if (previewsSeen.has(cid)) {
|
|
2164
|
+
errors.push("Phase " + id + ": duplicate preview of " + cid);
|
|
2165
|
+
continue;
|
|
2166
|
+
}
|
|
2167
|
+
previewsSeen.add(cid);
|
|
2168
|
+
previewPhase.set(cid, order);
|
|
2169
|
+
introductions.push({ concept_id: cid, aspect, note: String(ri.note || "") });
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2155
2172
|
if (aspect === "advanced") {
|
|
2156
2173
|
const first = newIntroPhase.get(cid);
|
|
2157
2174
|
if (first === void 0) {
|
|
@@ -2199,10 +2216,17 @@ function auditPhasePlan(plan, features, concepts, links, warnings, log) {
|
|
|
2199
2216
|
}
|
|
2200
2217
|
for (const [cid, consumerOrder] of firstConsumerPhase) {
|
|
2201
2218
|
const intro = newIntroPhase.get(cid);
|
|
2202
|
-
|
|
2219
|
+
const prev = previewPhase.get(cid);
|
|
2220
|
+
if (intro === void 0 && prev === void 0) {
|
|
2203
2221
|
errors.push("Concept " + cid + " is consumed from phase " + consumerOrder + " but never introduced in any phase");
|
|
2204
|
-
} else if (intro > consumerOrder) {
|
|
2205
|
-
errors.push("Concept " + cid + " introduced in phase " + intro + " but first consumed in phase " + consumerOrder + " - introduction must come no later than first consumption");
|
|
2222
|
+
} else if (intro !== void 0 && intro > consumerOrder && (prev === void 0 || prev > consumerOrder)) {
|
|
2223
|
+
errors.push("Concept " + cid + " introduced in phase " + intro + " but first consumed in phase " + consumerOrder + " - introduction must come no later than first consumption (or a preview must cover the dependency)");
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
for (const [cid, pOrder] of previewPhase) {
|
|
2227
|
+
const anchor = newIntroPhase.get(cid);
|
|
2228
|
+
if (anchor !== void 0 && anchor <= pOrder) {
|
|
2229
|
+
errors.push("Concept " + cid + " previewed in phase " + pOrder + " but fully introduced in phase " + anchor + " - preview must precede the anchor introduction");
|
|
2206
2230
|
}
|
|
2207
2231
|
}
|
|
2208
2232
|
return { phases, errors };
|
|
@@ -2218,7 +2242,7 @@ async function decomposePhases(args) {
|
|
|
2218
2242
|
const linkList = links.map(
|
|
2219
2243
|
(l) => "- " + l.feature_id + " -> " + l.concept_id + " (" + l.depth + ")"
|
|
2220
2244
|
).join("\n") || "(none)";
|
|
2221
|
-
const systemPrompt =
|
|
2245
|
+
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.\n9. Return JSON only.';
|
|
2222
2246
|
const baseUserPrompt = "FEATURES:\n" + featureList + "\n\nCONCEPTS:\n" + conceptList + "\n\nFEATURE-CONCEPT LINKS:\n" + linkList + "\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";
|
|
2223
2247
|
const MAX_DECOMPOSE_ATTEMPTS = 3;
|
|
2224
2248
|
let auditErrors = [];
|
|
@@ -2256,6 +2280,6 @@ async function decomposePhases(args) {
|
|
|
2256
2280
|
return phases;
|
|
2257
2281
|
}
|
|
2258
2282
|
|
|
2259
|
-
export { CIO_CODE_RE, CONCEPT_CODE_RE, LEARNER_CLAUSE, SIO_CODE_RE, ULO_CODE_RE, assignConceptCodes, auditDepthLayers, auditSyllabusCoverage, breakPrerequisiteCycles, cioActionSlug, cioCode, conceptCodeFromName, createLlmClient, detectPrerequisiteCycles, escalateAndMapConcepts, extractFeatureSteps, extractFeatureStepsBatched, extractProjectOverview, extractScaffold, generateHybridGraph, generateKnowledgeGraph, llmChatJson, sioCode, standardStatement, techTagFor, uloCode, verifyKnowledgeGraph, verifyProjectGraph };
|
|
2260
|
-
//# sourceMappingURL=chunk-
|
|
2261
|
-
//# sourceMappingURL=chunk-
|
|
2283
|
+
export { CIO_CODE_RE, CONCEPT_CODE_RE, LEARNER_CLAUSE, SIO_CODE_RE, ULO_CODE_RE, assignConceptCodes, auditDepthLayers, auditPhasePlan, auditSyllabusCoverage, breakPrerequisiteCycles, cioActionSlug, cioCode, conceptCodeFromName, createLlmClient, detectPrerequisiteCycles, escalateAndMapConcepts, extractFeatureSteps, extractFeatureStepsBatched, extractProjectOverview, extractScaffold, generateHybridGraph, generateKnowledgeGraph, llmChatJson, sioCode, standardStatement, techTagFor, uloCode, verifyKnowledgeGraph, verifyProjectGraph };
|
|
2284
|
+
//# sourceMappingURL=chunk-HILSUZOF.mjs.map
|
|
2285
|
+
//# sourceMappingURL=chunk-HILSUZOF.mjs.map
|