noteconnection 1.6.8 → 1.8.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 +674 -21
- package/README.md +258 -64
- package/dist/src/agent_workspace.contract.parity.test.js +475 -0
- package/dist/src/agent_workspace.frontend.test.js +9989 -0
- package/dist/src/agent_workspace.locale.contract.test.js +95 -0
- package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
- package/dist/src/copy.assets.contract.test.js +130 -0
- package/dist/src/core/PathBridge.js +28 -3
- package/dist/src/export/WorkspaceExportBundle.js +1130 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
- package/dist/src/export/index.js +18 -0
- package/dist/src/export/types.js +2 -0
- package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
- package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
- package/dist/src/foundation.release.evidence.contract.test.js +406 -0
- package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
- package/dist/src/frontend/README.md +258 -64
- package/dist/src/frontend/agent_workspace.js +5353 -0
- package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
- package/dist/src/frontend/analysis.js +31 -4
- package/dist/src/frontend/app.js +3597 -141
- package/dist/src/frontend/focus_mode_interactions.js +33 -0
- package/dist/src/frontend/godot_future_path_renderer.js +540 -0
- package/dist/src/frontend/godot_tree_interactions.js +178 -0
- package/dist/src/frontend/graph_state.mjs +105 -0
- package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
- package/dist/src/frontend/i18n.mjs +186 -0
- package/dist/src/frontend/index.html +641 -266
- package/dist/src/frontend/layout_gpu.js +12 -4
- package/dist/src/frontend/locales/en.json +721 -5
- package/dist/src/frontend/locales/zh.json +721 -5
- package/dist/src/frontend/main.mjs +60 -0
- package/dist/src/frontend/markdown_runtime.js +827 -0
- package/dist/src/frontend/notemd.css +49 -0
- package/dist/src/frontend/notemd.html +7 -1
- package/dist/src/frontend/notemd.js +64 -0
- package/dist/src/frontend/path.html +107 -0
- package/dist/src/frontend/path_app.js +2189 -150
- package/dist/src/frontend/path_layout.mjs +143 -0
- package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
- package/dist/src/frontend/path_modules_bridge.js +486 -0
- package/dist/src/frontend/path_state.mjs +118 -0
- package/dist/src/frontend/path_styles.css +146 -0
- package/dist/src/frontend/path_worker_bridge.mjs +85 -0
- package/dist/src/frontend/reader.js +522 -27
- package/dist/src/frontend/runtime_bridge.js +67 -54
- package/dist/src/frontend/runtime_bridge.mjs +279 -0
- package/dist/src/frontend/settings.js +130 -12
- package/dist/src/frontend/simulationWorker.js +241 -6
- package/dist/src/frontend/source_manager.js +190 -21
- package/dist/src/frontend/styles.css +2853 -72
- package/dist/src/frontend/workbench_state.mjs +101 -0
- package/dist/src/frontend/workspace_panes.js +10168 -0
- package/dist/src/frontend.locale.contract.test.js +62 -0
- package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
- package/dist/src/indexing/IndexLifecycle.js +195 -0
- package/dist/src/indexing/IndexLifecycle.test.js +49 -0
- package/dist/src/indexing/SegmentBuilder.js +64 -0
- package/dist/src/indexing/UnitBuilder.js +48 -0
- package/dist/src/indexing/types.js +2 -0
- package/dist/src/knowledge.api.contract.test.js +170 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
- package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
- package/dist/src/learning/answerReleaseReview.js +4319 -0
- package/dist/src/learning/answerReleaseReview.test.js +2888 -0
- package/dist/src/learning/api.js +2 -0
- package/dist/src/learning/conversationComposer.js +1480 -0
- package/dist/src/learning/conversationComposer.test.js +1817 -0
- package/dist/src/learning/domains/ConversationManager.js +53 -0
- package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
- package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
- package/dist/src/learning/domains/MasteryEngine.js +387 -0
- package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
- package/dist/src/learning/domains/QualityEvaluator.js +307 -0
- package/dist/src/learning/domains/TutorRouter.js +313 -0
- package/dist/src/learning/domains/index.js +33 -0
- package/dist/src/learning/domains/types.js +7 -0
- package/dist/src/learning/errors.js +29 -0
- package/dist/src/learning/evidenceContextAssembler.js +1176 -0
- package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
- package/dist/src/learning/graphContextAssembler.js +870 -0
- package/dist/src/learning/graphContextAssembler.test.js +1033 -0
- package/dist/src/learning/index.js +28 -0
- package/dist/src/learning/queryBackend.js +1898 -0
- package/dist/src/learning/queryBackend.test.js +955 -0
- package/dist/src/learning/ragContextPack.js +257 -0
- package/dist/src/learning/ragContextPack.test.js +160 -0
- package/dist/src/learning/ragPublicText.js +38 -0
- package/dist/src/learning/ragSufficiencyJudge.js +161 -0
- package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
- package/dist/src/learning/requestNormalization.js +198 -0
- package/dist/src/learning/runtimeCapability.js +4677 -0
- package/dist/src/learning/runtimeCapability.test.js +3635 -0
- package/dist/src/learning/store.js +1240 -0
- package/dist/src/learning/store.test.js +1126 -0
- package/dist/src/learning/tutorAdapter.js +2 -0
- package/dist/src/learning/types.js +2 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
- package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
- package/dist/src/lfs.asset.policy.contract.test.js +153 -0
- package/dist/src/license.policy.contract.test.js +66 -0
- package/dist/src/memory/MemoryGovernance.js +74 -0
- package/dist/src/memory/MemoryGovernance.test.js +46 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
- package/dist/src/middleware/auth.js +17 -0
- package/dist/src/middleware/body-parser.js +45 -0
- package/dist/src/middleware/cors.js +44 -0
- package/dist/src/middleware/index.js +21 -0
- package/dist/src/middleware/request-trace.js +96 -0
- package/dist/src/notemd/AppConfigToml.js +6 -4
- package/dist/src/notemd/MermaidProcessor.js +400 -50
- package/dist/src/notemd/NotemdService.js +498 -13
- package/dist/src/notemd/PromptManager.js +15 -0
- package/dist/src/notemd/cli/commands.js +357 -0
- package/dist/src/notemd/cli/dispatcher.js +225 -0
- package/dist/src/notemd/cli/index.js +169 -0
- package/dist/src/notemd/cli/parser.js +68 -0
- package/dist/src/notemd/cli/types.js +2 -0
- package/dist/src/notemd/constants.js +43 -0
- package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
- package/dist/src/notemd/diagram/diagramSpec.js +79 -0
- package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
- package/dist/src/notemd/diagram/intent.js +95 -0
- package/dist/src/notemd/diagram/planner.js +71 -0
- package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
- package/dist/src/notemd/diagram/types.js +18 -0
- package/dist/src/notemd/index.js +26 -0
- package/dist/src/notemd/operations/capabilityManifest.js +23 -0
- package/dist/src/notemd/operations/cliContracts.js +17 -0
- package/dist/src/notemd/operations/configProfileCommands.js +85 -0
- package/dist/src/notemd/operations/registry.contract.test.js +95 -0
- package/dist/src/notemd/operations/registry.js +991 -0
- package/dist/src/notemd/operations/types.js +2 -0
- package/dist/src/notemd/providerDiagnostics.js +220 -0
- package/dist/src/notemd/providerProfiles.js +42 -0
- package/dist/src/notemd/providerTemplates.js +231 -0
- package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
- package/dist/src/notemd/search/SearchManager.js +13 -0
- package/dist/src/notemd/search/SearchProvider.js +2 -0
- package/dist/src/notemd/search/TavilyProvider.js +44 -0
- package/dist/src/notemd.agent.manifest.test.js +85 -0
- package/dist/src/notemd.api.contract.test.js +14 -1
- package/dist/src/notemd.app_config_toml.test.js +2 -1
- package/dist/src/notemd.batch.workflow.test.js +117 -0
- package/dist/src/notemd.cli.e2e.test.js +136 -0
- package/dist/src/notemd.core.test.js +51 -0
- package/dist/src/notemd.diagram.pipeline.test.js +233 -0
- package/dist/src/notemd.providerTemplates.test.js +34 -0
- package/dist/src/notemd.server.integration.test.js +143 -35
- package/dist/src/notemd.workflow.pipeline.test.js +162 -0
- package/dist/src/pathbridge.handshake.contract.test.js +16 -2
- package/dist/src/pathmode.background.contract.test.js +69 -0
- package/dist/src/pathmode.settings.api.contract.test.js +9 -0
- package/dist/src/pkg.sidecar.contract.test.js +9 -3
- package/dist/src/platform/ExportProfile.js +58 -0
- package/dist/src/platform/PlatformCapabilities.js +45 -0
- package/dist/src/platform/PlatformCapabilities.test.js +30 -0
- package/dist/src/platform/RenderMaterializer.js +33 -0
- package/dist/src/platform/RenderMaterializer.test.js +32 -0
- package/dist/src/query_backend.external_http.integration.test.js +410 -0
- package/dist/src/reader_renderer.js +404 -3
- package/dist/src/reader_renderer.test.js +87 -0
- package/dist/src/release.godot.mirror.contract.test.js +73 -0
- package/dist/src/resources/ResourceRegistry.js +223 -0
- package/dist/src/resources/ResourceRegistry.test.js +61 -0
- package/dist/src/resources/types.js +2 -0
- package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
- package/dist/src/routes/data.js +267 -0
- package/dist/src/routes/diagnostics.js +51 -0
- package/dist/src/routes/index.js +23 -0
- package/dist/src/routes/knowledge.js +968 -0
- package/dist/src/routes/markdown.js +287 -0
- package/dist/src/routes/notemd.js +565 -0
- package/dist/src/routes/registry.contract.test.js +130 -0
- package/dist/src/routes/render.js +285 -0
- package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
- package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
- package/dist/src/routes/settings.js +6 -0
- package/dist/src/routes/staticFiles.js +94 -0
- package/dist/src/routes/types.js +2 -0
- package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
- package/dist/src/server.js +11090 -1549
- package/dist/src/server.migration.test.js +193 -21
- package/dist/src/server.port.fallback.contract.test.js +63 -0
- package/dist/src/session/SessionStateStore.js +81 -0
- package/dist/src/session/SessionStateStore.test.js +58 -0
- package/dist/src/session/types.js +2 -0
- package/dist/src/settings.runtime.contract.test.js +50 -0
- package/dist/src/shared/types.contract.test.js +107 -0
- package/dist/src/shared/types.js +22 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
- package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
- package/dist/src/source_manager.loadflow.test.js +46 -0
- package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
- package/dist/src/tauri.frontend.build.contract.test.js +60 -0
- package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
- package/dist/src/utils/RuntimePaths.js +4 -13
- package/dist/src/utils/platform.js +153 -0
- package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
- package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
- package/dist/src/workflows/types.js +2 -0
- package/dist/src/workspace/WorkspaceRegistry.js +122 -0
- package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
- package/dist/src/workspace/types.js +2 -0
- package/package.json +61 -10
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MasteryEngine = void 0;
|
|
4
|
+
class MasteryEngine {
|
|
5
|
+
constructor(platform) {
|
|
6
|
+
this.platform = platform;
|
|
7
|
+
this.pathGenerationCount = 0;
|
|
8
|
+
this.sessionBuildCount = 0;
|
|
9
|
+
this.sessionExecutionCount = 0;
|
|
10
|
+
this.actionExecutionCount = 0;
|
|
11
|
+
this.masteryDiagnosticCount = 0;
|
|
12
|
+
this.lastPathGeneratedAt = null;
|
|
13
|
+
// Domain-level analysis state
|
|
14
|
+
this.masteryTrendSnapshots = [];
|
|
15
|
+
this.misconceptionTrendSnapshots = [];
|
|
16
|
+
this.pathQualityHistory = [];
|
|
17
|
+
this.sessionBudgetViolations = [];
|
|
18
|
+
// Domain budget constraints
|
|
19
|
+
this.budgets = {
|
|
20
|
+
maxActionsPerSession: 60,
|
|
21
|
+
maxEstimatedMinutesPerSession: 480,
|
|
22
|
+
minEvidenceCoveragePct: 30,
|
|
23
|
+
maxActionsPerAtom: 5,
|
|
24
|
+
minActionKindDiversity: 2,
|
|
25
|
+
};
|
|
26
|
+
// ─── Private: atom action budget ────────────────────────────────
|
|
27
|
+
this.atomActionCounts = new Map();
|
|
28
|
+
}
|
|
29
|
+
async diagnoseMastery(r) {
|
|
30
|
+
this.masteryDiagnosticCount++;
|
|
31
|
+
const response = await this.platform.diagnoseMastery(r);
|
|
32
|
+
// Domain-level mastery trend analysis
|
|
33
|
+
this.recordMasteryTrendSnapshot(response);
|
|
34
|
+
const trend = this.computeMasteryTrend(10);
|
|
35
|
+
return {
|
|
36
|
+
...response,
|
|
37
|
+
_domain: {
|
|
38
|
+
diagnosticNumber: this.masteryDiagnosticCount,
|
|
39
|
+
trend,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async queryMisconceptions(r) {
|
|
44
|
+
const response = await this.platform.queryMasteryMisconceptions(r);
|
|
45
|
+
// Domain-level misconception trend analysis
|
|
46
|
+
this.recordMisconceptionSnapshot(response);
|
|
47
|
+
const trend = this.computeMisconceptionTrend(8);
|
|
48
|
+
// Augment misconception items with domain-level risk classification
|
|
49
|
+
const items = (response?.items || []).map((item) => ({
|
|
50
|
+
...item,
|
|
51
|
+
riskLevel: this.classifyMisconceptionRisk(item),
|
|
52
|
+
}));
|
|
53
|
+
return { ...response, items, _domain: { trend } };
|
|
54
|
+
}
|
|
55
|
+
async buildLearningPath(r) {
|
|
56
|
+
this.pathGenerationCount++;
|
|
57
|
+
this.lastPathGeneratedAt = new Date().toISOString();
|
|
58
|
+
this.validatePathRequest(r);
|
|
59
|
+
// Domain-level budget validation for path parameters
|
|
60
|
+
this.validatePathBudgets(r);
|
|
61
|
+
const response = await this.platform.buildLearningPath(r);
|
|
62
|
+
// Record path quality metrics
|
|
63
|
+
this.recordPathQuality(response);
|
|
64
|
+
return this.augmentPathResponse(response);
|
|
65
|
+
}
|
|
66
|
+
async buildStudySession(r) {
|
|
67
|
+
this.sessionBuildCount++;
|
|
68
|
+
// Domain-level session budget validation
|
|
69
|
+
this.validateSessionBudgets(r);
|
|
70
|
+
const response = await this.platform.buildStudySession(r);
|
|
71
|
+
// Domain-level session quality analysis
|
|
72
|
+
const quality = this.analyzeSessionQuality(response);
|
|
73
|
+
return { ...response, _domain: { sessionBuildNumber: this.sessionBuildCount, quality } };
|
|
74
|
+
}
|
|
75
|
+
async querySessionHistory(r) {
|
|
76
|
+
const response = await this.platform.queryStudySessionHistory(r);
|
|
77
|
+
// Domain-level history aggregation
|
|
78
|
+
const records = response?.records || [];
|
|
79
|
+
const aggregated = this.aggregateSessionHistory(records);
|
|
80
|
+
return { ...response, _domain: { aggregated } };
|
|
81
|
+
}
|
|
82
|
+
async executeSessionAction(r) {
|
|
83
|
+
this.actionExecutionCount++;
|
|
84
|
+
// Validate action against per-atom budget
|
|
85
|
+
const atomBudget = this.checkAtomActionBudget(r);
|
|
86
|
+
if (!atomBudget.ok) {
|
|
87
|
+
this.sessionBudgetViolations.push({
|
|
88
|
+
generatedAt: new Date().toISOString(),
|
|
89
|
+
violation: `atom_action_budget:${r?.action?.atomId}`,
|
|
90
|
+
observed: atomBudget.count,
|
|
91
|
+
limit: this.budgets.maxActionsPerAtom,
|
|
92
|
+
});
|
|
93
|
+
this.pruneViolations();
|
|
94
|
+
}
|
|
95
|
+
const response = await this.platform.executeStudySessionAction(r);
|
|
96
|
+
return response;
|
|
97
|
+
}
|
|
98
|
+
async executeSessionPlan(r) {
|
|
99
|
+
this.sessionExecutionCount++;
|
|
100
|
+
// Domain-level plan validation
|
|
101
|
+
this.validatePlanExecution(r);
|
|
102
|
+
const response = await this.platform.executeStudySessionPlan(r);
|
|
103
|
+
// Augment with domain-level execution telemetry
|
|
104
|
+
return {
|
|
105
|
+
...response,
|
|
106
|
+
_domain: {
|
|
107
|
+
executionNumber: this.sessionExecutionCount,
|
|
108
|
+
planSize: Array.isArray(r?.actions) ? r.actions.length : 0,
|
|
109
|
+
pathStrategy: r?.pathStrategy ?? 'default',
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async updateOrchestrationConfig(r) {
|
|
114
|
+
return this.platform.updateStudySessionOrchestrationConfig(r);
|
|
115
|
+
}
|
|
116
|
+
// ─── Public accessors ───────────────────────────────────────────
|
|
117
|
+
getPathGenerationCount() { return this.pathGenerationCount; }
|
|
118
|
+
getSessionExecutionCount() { return this.sessionExecutionCount; }
|
|
119
|
+
getDiagnosticsSummary() {
|
|
120
|
+
return {
|
|
121
|
+
masteryDiagnosticCount: this.masteryDiagnosticCount,
|
|
122
|
+
pathGenerationCount: this.pathGenerationCount,
|
|
123
|
+
lastPathGeneratedAt: this.lastPathGeneratedAt,
|
|
124
|
+
sessionBuildCount: this.sessionBuildCount,
|
|
125
|
+
sessionExecutionCount: this.sessionExecutionCount,
|
|
126
|
+
actionExecutionCount: this.actionExecutionCount,
|
|
127
|
+
masteryTrend: this.computeMasteryTrend(5),
|
|
128
|
+
misconceptionTrend: this.computeMisconceptionTrend(5),
|
|
129
|
+
budgetViolationCount: this.sessionBudgetViolations.length,
|
|
130
|
+
recentBudgetViolations: this.sessionBudgetViolations.slice(-5),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
getMasteryTrendSnapshots() { return [...this.masteryTrendSnapshots]; }
|
|
134
|
+
getBudgetViolations() { return [...this.sessionBudgetViolations]; }
|
|
135
|
+
// ─── Private: validation ────────────────────────────────────────
|
|
136
|
+
validatePathRequest(r) {
|
|
137
|
+
if (!r)
|
|
138
|
+
throw new Error('Learning path request is required.');
|
|
139
|
+
const targetId = String(r?.targetId ?? '').trim();
|
|
140
|
+
if (!targetId && !r?.targetIds?.length) {
|
|
141
|
+
throw new Error('At least one targetId is required to build a learning path.');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
validatePathBudgets(r) {
|
|
145
|
+
const maxMastery = Number(r?.maxMasteryPaths);
|
|
146
|
+
const maxDivergence = Number(r?.maxDivergencePaths);
|
|
147
|
+
if (maxMastery > 12)
|
|
148
|
+
throw new Error('maxMasteryPaths exceeds domain limit of 12.');
|
|
149
|
+
if (maxDivergence > 12)
|
|
150
|
+
throw new Error('maxDivergencePaths exceeds domain limit of 12.');
|
|
151
|
+
}
|
|
152
|
+
validateSessionBudgets(r) {
|
|
153
|
+
const maxActions = Number(r?.maxActions);
|
|
154
|
+
if (maxActions > this.budgets.maxActionsPerSession) {
|
|
155
|
+
throw new Error(`maxActions (${maxActions}) exceeds domain budget of ${this.budgets.maxActionsPerSession}.`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
validatePlanExecution(r) {
|
|
159
|
+
if (!r)
|
|
160
|
+
throw new Error('Study session plan execution request is required.');
|
|
161
|
+
if (!r?.userId)
|
|
162
|
+
throw new Error('userId is required for plan execution.');
|
|
163
|
+
const actions = Array.isArray(r?.actions) ? r.actions : [];
|
|
164
|
+
if (actions.length === 0 && !r?.focusAtomIds?.length) {
|
|
165
|
+
throw new Error('Plan must contain at least one action or focusAtomId.');
|
|
166
|
+
}
|
|
167
|
+
if (actions.length > this.budgets.maxActionsPerSession) {
|
|
168
|
+
throw new Error(`Plan action count (${actions.length}) exceeds session budget of ${this.budgets.maxActionsPerSession}.`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ─── Private: augmentation ──────────────────────────────────────
|
|
172
|
+
augmentPathResponse(response) {
|
|
173
|
+
const nodes = Array.isArray(response?.nodes) ? response.nodes : [];
|
|
174
|
+
const masteryPaths = Array.isArray(response?.masteryPaths) ? response.masteryPaths : [];
|
|
175
|
+
const divergencePaths = Array.isArray(response?.divergencePaths) ? response.divergencePaths : [];
|
|
176
|
+
// Compute prerequisite coverage
|
|
177
|
+
const prerequisiteCoveragePct = this.computePrerequisiteCoverage(masteryPaths, divergencePaths);
|
|
178
|
+
return {
|
|
179
|
+
...response,
|
|
180
|
+
_domain: {
|
|
181
|
+
pathLength: nodes.length,
|
|
182
|
+
generatedAt: this.lastPathGeneratedAt,
|
|
183
|
+
generationNumber: this.pathGenerationCount,
|
|
184
|
+
hasPrerequisites: nodes.some((n) => n?.prerequisites?.length > 0),
|
|
185
|
+
estimatedDurationMinutes: nodes.length * 15,
|
|
186
|
+
prerequisiteCoveragePct,
|
|
187
|
+
masteryPathCount: masteryPaths.length,
|
|
188
|
+
divergencePathCount: divergencePaths.length,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
// ─── Private: mastery trend analysis ────────────────────────────
|
|
193
|
+
recordMasteryTrendSnapshot(response) {
|
|
194
|
+
const summary = response?.summary || {};
|
|
195
|
+
const before = Number(summary.averageMasteryBefore || 0);
|
|
196
|
+
const after = Number(summary.averageMasteryAfter || 0);
|
|
197
|
+
const gainPct = before > 0 ? Number(((after - before) / before * 100).toFixed(2)) : 0;
|
|
198
|
+
this.masteryTrendSnapshots.push({
|
|
199
|
+
generatedAt: new Date().toISOString(),
|
|
200
|
+
averageMasteryBefore: before,
|
|
201
|
+
averageMasteryAfter: after,
|
|
202
|
+
updatedCount: summary.updatedCount || 0,
|
|
203
|
+
gainPct,
|
|
204
|
+
});
|
|
205
|
+
if (this.masteryTrendSnapshots.length > 50)
|
|
206
|
+
this.masteryTrendSnapshots.shift();
|
|
207
|
+
}
|
|
208
|
+
computeMasteryTrend(n) {
|
|
209
|
+
const window = this.masteryTrendSnapshots.slice(-n);
|
|
210
|
+
if (window.length < 2) {
|
|
211
|
+
return {
|
|
212
|
+
direction: 'insufficient_data',
|
|
213
|
+
recentGainPct: window[0]?.gainPct ?? 0,
|
|
214
|
+
windowAvgGainPct: window[0]?.gainPct ?? 0,
|
|
215
|
+
snapshots: window.length,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const mid = Math.floor(window.length / 2);
|
|
219
|
+
const recentAvg = window.slice(-mid).reduce((s, e) => s + e.gainPct, 0) / mid;
|
|
220
|
+
const earlierAvg = window.slice(0, mid).reduce((s, e) => s + e.gainPct, 0) / mid;
|
|
221
|
+
const delta = recentAvg - earlierAvg;
|
|
222
|
+
return {
|
|
223
|
+
direction: delta > 3 ? 'accelerating' : delta > 0.5 ? 'improving' : delta < -3 ? 'declining' : delta < -0.5 ? 'slowing' : 'stable',
|
|
224
|
+
recentGainPct: window[window.length - 1].gainPct,
|
|
225
|
+
windowAvgGainPct: Number((window.reduce((s, e) => s + e.gainPct, 0) / window.length).toFixed(2)),
|
|
226
|
+
snapshots: window.length,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// ─── Private: misconception trend analysis ──────────────────────
|
|
230
|
+
recordMisconceptionSnapshot(response) {
|
|
231
|
+
const items = Array.isArray(response?.items) ? response.items : [];
|
|
232
|
+
const highSeverityCount = items.filter((i) => (i.severityScore || 0) >= 0.7).length;
|
|
233
|
+
const averageSeverity = items.length > 0
|
|
234
|
+
? Number((items.reduce((s, i) => s + (i.severityScore || 0), 0) / items.length).toFixed(4))
|
|
235
|
+
: 0;
|
|
236
|
+
const topItem = items.length > 0 ? items[0] : null;
|
|
237
|
+
this.misconceptionTrendSnapshots.push({
|
|
238
|
+
generatedAt: new Date().toISOString(),
|
|
239
|
+
totalItems: items.length,
|
|
240
|
+
averageSeverity,
|
|
241
|
+
highSeverityCount,
|
|
242
|
+
topErrorTag: topItem?.errorTag ?? null,
|
|
243
|
+
});
|
|
244
|
+
if (this.misconceptionTrendSnapshots.length > 50)
|
|
245
|
+
this.misconceptionTrendSnapshots.shift();
|
|
246
|
+
}
|
|
247
|
+
computeMisconceptionTrend(n) {
|
|
248
|
+
const window = this.misconceptionTrendSnapshots.slice(-n);
|
|
249
|
+
if (window.length < 2) {
|
|
250
|
+
return {
|
|
251
|
+
direction: 'insufficient_data',
|
|
252
|
+
recentAvgSeverity: window[0]?.averageSeverity ?? 0,
|
|
253
|
+
highSeverityTrend: 'stable',
|
|
254
|
+
snapshots: window.length,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const mid = Math.floor(window.length / 2);
|
|
258
|
+
const recentAvg = window.slice(-mid).reduce((s, e) => s + e.averageSeverity, 0) / mid;
|
|
259
|
+
const earlierAvg = window.slice(0, mid).reduce((s, e) => s + e.averageSeverity, 0) / mid;
|
|
260
|
+
const delta = recentAvg - earlierAvg;
|
|
261
|
+
const recentHigh = window.slice(-mid).reduce((s, e) => s + e.highSeverityCount, 0);
|
|
262
|
+
const earlierHigh = window.slice(0, mid).reduce((s, e) => s + e.highSeverityCount, 0);
|
|
263
|
+
return {
|
|
264
|
+
direction: delta < -0.05 ? 'resolving' : delta > 0.05 ? 'worsening' : 'stable',
|
|
265
|
+
recentAvgSeverity: Number(recentAvg.toFixed(4)),
|
|
266
|
+
highSeverityTrend: recentHigh < earlierHigh ? 'decreasing' : recentHigh > earlierHigh ? 'increasing' : 'stable',
|
|
267
|
+
snapshots: window.length,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
classifyMisconceptionRisk(item) {
|
|
271
|
+
const severity = Number(item?.severityScore || 0);
|
|
272
|
+
const count = Number(item?.count || 0);
|
|
273
|
+
if (severity >= 0.8 && count >= 5)
|
|
274
|
+
return 'critical';
|
|
275
|
+
if (severity >= 0.6)
|
|
276
|
+
return 'high';
|
|
277
|
+
if (severity >= 0.35)
|
|
278
|
+
return 'moderate';
|
|
279
|
+
return 'low';
|
|
280
|
+
}
|
|
281
|
+
// ─── Private: path quality metrics ──────────────────────────────
|
|
282
|
+
recordPathQuality(response) {
|
|
283
|
+
const masteryPaths = Array.isArray(response?.masteryPaths) ? response.masteryPaths : [];
|
|
284
|
+
const divergencePaths = Array.isArray(response?.divergencePaths) ? response.divergencePaths : [];
|
|
285
|
+
const allActions = [...masteryPaths, ...divergencePaths].flatMap((p) => p.actions || []);
|
|
286
|
+
const totalNodes = allActions.length;
|
|
287
|
+
const prerequisiteCoveragePct = this.computePrerequisiteCoverage(masteryPaths, divergencePaths);
|
|
288
|
+
const averagePriority = totalNodes > 0
|
|
289
|
+
? Number((allActions.reduce((s, a) => s + (a.priority || 0), 0) / totalNodes).toFixed(2))
|
|
290
|
+
: 0;
|
|
291
|
+
const actionKindDistribution = {};
|
|
292
|
+
for (const action of allActions) {
|
|
293
|
+
const kind = String(action.kind || 'unknown');
|
|
294
|
+
actionKindDistribution[kind] = (actionKindDistribution[kind] || 0) + 1;
|
|
295
|
+
}
|
|
296
|
+
this.pathQualityHistory.push({
|
|
297
|
+
generatedAt: new Date().toISOString(),
|
|
298
|
+
totalNodes,
|
|
299
|
+
prerequisiteCoveragePct,
|
|
300
|
+
averagePriority,
|
|
301
|
+
actionKindDistribution,
|
|
302
|
+
});
|
|
303
|
+
if (this.pathQualityHistory.length > 50)
|
|
304
|
+
this.pathQualityHistory.shift();
|
|
305
|
+
}
|
|
306
|
+
computePrerequisiteCoverage(masteryPaths, divergencePaths) {
|
|
307
|
+
const allPaths = [...masteryPaths, ...divergencePaths];
|
|
308
|
+
let totalPrerequisites = 0;
|
|
309
|
+
let coveredPrerequisites = 0;
|
|
310
|
+
for (const path of allPaths) {
|
|
311
|
+
const prerequisites = Array.isArray(path?.prerequisites) ? path.prerequisites : [];
|
|
312
|
+
totalPrerequisites += prerequisites.length;
|
|
313
|
+
for (const prereq of prerequisites) {
|
|
314
|
+
const prereqId = String(prereq?.id || prereq);
|
|
315
|
+
const isCovered = allPaths.some((p) => p.targetAtomId === prereqId ||
|
|
316
|
+
(p.actions || []).some((a) => a.atomId === prereqId));
|
|
317
|
+
if (isCovered)
|
|
318
|
+
coveredPrerequisites++;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return totalPrerequisites > 0
|
|
322
|
+
? Number(((coveredPrerequisites / totalPrerequisites) * 100).toFixed(1))
|
|
323
|
+
: 100;
|
|
324
|
+
}
|
|
325
|
+
// ─── Private: session quality analysis ──────────────────────────
|
|
326
|
+
analyzeSessionQuality(response) {
|
|
327
|
+
const actions = Array.isArray(response?.actions) ? response.actions : [];
|
|
328
|
+
const summary = response?.summary || {};
|
|
329
|
+
const kinds = new Set(actions.map((a) => String(a.kind || '')));
|
|
330
|
+
const evidenceCoveragePct = (summary.evidenceCoverageRatio ?? 0) * 100;
|
|
331
|
+
const averagePriority = actions.length > 0
|
|
332
|
+
? Number((actions.reduce((s, a) => s + (a.priority || 0), 0) / actions.length).toFixed(2))
|
|
333
|
+
: 0;
|
|
334
|
+
const budgetWarnings = [];
|
|
335
|
+
if (actions.length > this.budgets.maxActionsPerSession * 0.8) {
|
|
336
|
+
budgetWarnings.push(`Action count (${actions.length}) near budget limit (${this.budgets.maxActionsPerSession}).`);
|
|
337
|
+
}
|
|
338
|
+
if (evidenceCoveragePct < this.budgets.minEvidenceCoveragePct) {
|
|
339
|
+
budgetWarnings.push(`Evidence coverage (${Number(evidenceCoveragePct).toFixed(1)}%) below minimum (${this.budgets.minEvidenceCoveragePct}%).`);
|
|
340
|
+
}
|
|
341
|
+
if (kinds.size < this.budgets.minActionKindDiversity) {
|
|
342
|
+
budgetWarnings.push(`Action kind diversity (${kinds.size}) below recommended minimum (${this.budgets.minActionKindDiversity}).`);
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
actionKindDiversity: kinds.size,
|
|
346
|
+
evidenceCoveragePct: Number(evidenceCoveragePct.toFixed(1)),
|
|
347
|
+
averagePriority,
|
|
348
|
+
withinBudget: budgetWarnings.length === 0,
|
|
349
|
+
budgetWarnings,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
// ─── Private: session history aggregation ───────────────────────
|
|
353
|
+
aggregateSessionHistory(records) {
|
|
354
|
+
let totalActions = 0;
|
|
355
|
+
let masteryDeltaSum = 0;
|
|
356
|
+
let confidenceSum = 0;
|
|
357
|
+
for (const record of records) {
|
|
358
|
+
totalActions += Math.max(0, Math.floor(Number(record.executedCount || 0)));
|
|
359
|
+
masteryDeltaSum += Number(record.averageMasteryDelta || 0);
|
|
360
|
+
confidenceSum += Number(record.averageTutorConfidence || 0);
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
totalSessions: records.length,
|
|
364
|
+
totalActions,
|
|
365
|
+
averageMasteryDelta: records.length > 0
|
|
366
|
+
? Number((masteryDeltaSum / records.length).toFixed(6))
|
|
367
|
+
: 0,
|
|
368
|
+
averageTutorConfidence: records.length > 0
|
|
369
|
+
? Number((confidenceSum / records.length).toFixed(4))
|
|
370
|
+
: 0,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
checkAtomActionBudget(r) {
|
|
374
|
+
const atomId = String(r?.action?.atomId || '');
|
|
375
|
+
if (!atomId)
|
|
376
|
+
return { ok: true, count: 0 };
|
|
377
|
+
const count = (this.atomActionCounts.get(atomId) || 0) + 1;
|
|
378
|
+
this.atomActionCounts.set(atomId, count);
|
|
379
|
+
return { ok: count <= this.budgets.maxActionsPerAtom, count };
|
|
380
|
+
}
|
|
381
|
+
pruneViolations() {
|
|
382
|
+
if (this.sessionBudgetViolations.length > 100) {
|
|
383
|
+
this.sessionBudgetViolations.shift();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
exports.MasteryEngine = MasteryEngine;
|