@vue-skuilder/express 0.1.22 → 0.1.24

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.
@@ -1 +1 @@
1
- {"version":3,"file":"app-factory.d.ts","sourceRoot":"","sources":["../src/app-factory.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAK9B,OAAO,OAAO,MAAM,SAAS,CAAC;AAoB9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGzE,MAAM,WAAW,gBAAiB,SAAQ,OAAO,CAAC,OAAO;IACvD,IAAI,EAAE,aAAa,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AAwBhE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CA+LvE;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DzE"}
1
+ {"version":3,"file":"app-factory.d.ts","sourceRoot":"","sources":["../src/app-factory.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAK9B,OAAO,OAAO,MAAM,SAAS,CAAC;AAqB9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGzE,MAAM,WAAW,gBAAiB,SAAQ,OAAO,CAAC,OAAO;IACvD,IAAI,EAAE,aAAa,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AAwBhE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAgMvE;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DzE"}
@@ -15,6 +15,7 @@ import { classroomDbDesignDoc } from './design-docs.js';
15
15
  import logger from './logger.js';
16
16
  import logsRouter from './routes/logs.js';
17
17
  import authRouter from './routes/auth.js';
18
+ import orchestrationRouter from './routes/orchestration.js';
18
19
  import { applyUsersDesignDocs } from './couchdb/userDesignDocs.js';
19
20
  /**
20
21
  * Type guard to determine if config is ExpressServerConfig (programmatic usage)
@@ -61,6 +62,7 @@ export function createExpressApp(config) {
61
62
  }));
62
63
  app.use('/logs', logsRouter);
63
64
  app.use('/auth', authRouter);
65
+ app.use('/orchestration', orchestrationRouter);
64
66
  // Routes
65
67
  app.get('/courses', (_req, res) => {
66
68
  void (async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"app-factory.js","sourceRoot":"","sources":["../src/app-factory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app-factory.js","sourceRoot":"","sources":["../src/app-factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=orchestration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../../src/routes/orchestration.ts"],"names":[],"mappings":"AAkBA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAwaxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,374 @@
1
+ import { Router } from 'express';
2
+ import { requestIsAuthenticated } from '../couchdb/authentication.js';
3
+ import { useOrCreateCourseDB, getCouchDB } from '../couchdb/index.js';
4
+ import logger from '../logger.js';
5
+ import { aggregateOutcomesForGradient, computeStrategyGradient, runPeriodUpdate, getDefaultLearnableWeight, } from '@vue-skuilder/db';
6
+ const router = Router();
7
+ /**
8
+ * POST /orchestration/:courseId/update
9
+ *
10
+ * Trigger a period update for all strategies in a course.
11
+ * This aggregates user outcomes and adjusts strategy weights based on gradients.
12
+ *
13
+ * Requires authentication.
14
+ *
15
+ * Query params:
16
+ * - periodStart: ISO timestamp (optional, defaults to 7 days ago)
17
+ * - periodEnd: ISO timestamp (optional, defaults to now)
18
+ */
19
+ router.post('/:courseId/update', (req, res) => {
20
+ void (async () => {
21
+ try {
22
+ const auth = await requestIsAuthenticated(req);
23
+ if (!auth) {
24
+ res.status(401).json({ error: 'Unauthorized' });
25
+ return;
26
+ }
27
+ const { courseId } = req.params;
28
+ const periodEnd = req.query.periodEnd || new Date().toISOString();
29
+ const periodStart = req.query.periodStart ||
30
+ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
31
+ logger.info(`[Orchestration] Period update requested for course ${courseId} ` +
32
+ `(${periodStart} to ${periodEnd})`);
33
+ // 1. Get course DB and strategies
34
+ const courseDB = await useOrCreateCourseDB(courseId);
35
+ const strategiesResp = await courseDB.find({
36
+ selector: { docType: 'NAVIGATION_STRATEGY' },
37
+ });
38
+ const strategies = strategiesResp.docs;
39
+ if (strategies.length === 0) {
40
+ res.json({ message: 'No strategies found', updated: 0 });
41
+ return;
42
+ }
43
+ // 2. Aggregate user outcomes for this course
44
+ // Note: This queries across user DBs - requires admin access
45
+ const outcomes = await aggregateUserOutcomes(courseId, periodStart, periodEnd);
46
+ if (outcomes.length === 0) {
47
+ res.json({ message: 'No outcome records found', updated: 0 });
48
+ return;
49
+ }
50
+ logger.info(`[Orchestration] Found ${outcomes.length} outcome records for ${courseId}`);
51
+ // 3. Process each strategy
52
+ const results = [];
53
+ for (const strategy of strategies) {
54
+ const strategyId = strategy._id;
55
+ // Skip static weight strategies
56
+ if (strategy.staticWeight) {
57
+ logger.debug(`[Orchestration] Skipping static strategy ${strategyId}`);
58
+ continue;
59
+ }
60
+ // Get or create learning state
61
+ let existingState;
62
+ try {
63
+ existingState = (await courseDB.get(`STRATEGY_LEARNING_STATE::${courseId}::${strategyId}`));
64
+ }
65
+ catch {
66
+ // No existing state, that's fine
67
+ }
68
+ // Aggregate observations for this strategy
69
+ const observations = aggregateOutcomesForGradient(outcomes, strategyId);
70
+ if (observations.length < 3) {
71
+ logger.debug(`[Orchestration] Insufficient observations for ${strategyId} (${observations.length})`);
72
+ continue;
73
+ }
74
+ // Compute gradient
75
+ const gradient = computeStrategyGradient(observations);
76
+ if (!gradient) {
77
+ continue;
78
+ }
79
+ // Get current weight
80
+ const currentWeight = strategy.learnable || getDefaultLearnableWeight();
81
+ // Run update
82
+ const input = {
83
+ courseId,
84
+ strategyId,
85
+ currentWeight,
86
+ gradient,
87
+ existingState,
88
+ };
89
+ const result = runPeriodUpdate(input);
90
+ // Persist updated strategy
91
+ if (result.updated) {
92
+ const updatedStrategy = {
93
+ ...strategy,
94
+ learnable: result.newWeight,
95
+ };
96
+ await courseDB.insert(updatedStrategy);
97
+ }
98
+ // Persist learning state
99
+ await courseDB.insert(result.learningState);
100
+ results.push({
101
+ strategyId,
102
+ previousWeight: result.previousWeight.weight,
103
+ newWeight: result.newWeight.weight,
104
+ gradient: gradient.gradient,
105
+ rSquared: gradient.rSquared,
106
+ observations: observations.length,
107
+ });
108
+ }
109
+ res.json({
110
+ message: 'Period update complete',
111
+ courseId,
112
+ periodStart,
113
+ periodEnd,
114
+ outcomesProcessed: outcomes.length,
115
+ strategiesUpdated: results.filter((r) => r.previousWeight !== r.newWeight).length,
116
+ results,
117
+ });
118
+ }
119
+ catch (error) {
120
+ logger.error(`[Orchestration] Period update error: ${error}`);
121
+ res.status(500).json({ error: 'Period update failed', details: String(error) });
122
+ }
123
+ })();
124
+ });
125
+ /**
126
+ * GET /orchestration/:courseId/state
127
+ *
128
+ * Get current learning state for all strategies in a course.
129
+ */
130
+ router.get('/:courseId/state', (req, res) => {
131
+ void (async () => {
132
+ try {
133
+ const { courseId } = req.params;
134
+ const courseDB = await useOrCreateCourseDB(courseId);
135
+ const statesResp = await courseDB.find({
136
+ selector: { docType: 'STRATEGY_LEARNING_STATE' },
137
+ });
138
+ res.json({
139
+ courseId,
140
+ states: statesResp.docs,
141
+ });
142
+ }
143
+ catch (error) {
144
+ logger.error(`[Orchestration] Get state error: ${error}`);
145
+ res.status(500).json({ error: 'Failed to get state', details: String(error) });
146
+ }
147
+ })();
148
+ });
149
+ /**
150
+ * GET /orchestration/:courseId/strategy/:strategyId/history
151
+ *
152
+ * Get weight history for a specific strategy.
153
+ */
154
+ router.get('/:courseId/strategy/:strategyId/history', (req, res) => {
155
+ void (async () => {
156
+ try {
157
+ const { courseId, strategyId } = req.params;
158
+ const courseDB = await useOrCreateCourseDB(courseId);
159
+ const stateId = `STRATEGY_LEARNING_STATE::${courseId}::${strategyId}`;
160
+ try {
161
+ const state = (await courseDB.get(stateId));
162
+ res.json({
163
+ courseId,
164
+ strategyId,
165
+ currentWeight: state.currentWeight,
166
+ regression: state.regression,
167
+ history: state.history,
168
+ });
169
+ }
170
+ catch {
171
+ res.status(404).json({ error: 'No learning state found for this strategy' });
172
+ }
173
+ }
174
+ catch (error) {
175
+ logger.error(`[Orchestration] Get history error: ${error}`);
176
+ res.status(500).json({ error: 'Failed to get history', details: String(error) });
177
+ }
178
+ })();
179
+ });
180
+ /**
181
+ * GET /orchestration/:courseId/strategy/:strategyId/scatter
182
+ *
183
+ * Get scatter plot data (deviation vs outcome) for a specific strategy.
184
+ * Useful for visualizing the gradient and understanding the learning dynamics.
185
+ *
186
+ * Query params:
187
+ * - periodStart: ISO timestamp (optional, defaults to 7 days ago)
188
+ * - periodEnd: ISO timestamp (optional, defaults to now)
189
+ * - limit: max observations to return (optional, defaults to 1000)
190
+ */
191
+ router.get('/:courseId/strategy/:strategyId/scatter', (req, res) => {
192
+ void (async () => {
193
+ try {
194
+ const { courseId, strategyId } = req.params;
195
+ const periodEnd = req.query.periodEnd || new Date().toISOString();
196
+ const periodStart = req.query.periodStart ||
197
+ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
198
+ const limit = parseInt(req.query.limit || '1000', 10);
199
+ // Aggregate outcomes
200
+ const outcomes = await aggregateUserOutcomes(courseId, periodStart, periodEnd);
201
+ // Extract scatter data for this strategy
202
+ const scatterData = outcomes
203
+ .filter((outcome) => outcome.deviations[strategyId] !== undefined)
204
+ .map((outcome) => ({
205
+ deviation: outcome.deviations[strategyId],
206
+ outcome: outcome.outcomeValue,
207
+ userId: outcome.userId,
208
+ periodEnd: outcome.periodEnd,
209
+ }))
210
+ .slice(0, limit);
211
+ // Compute regression for visualization
212
+ const observations = aggregateOutcomesForGradient(outcomes, strategyId);
213
+ const gradient = observations.length >= 3 ? computeStrategyGradient(observations) : null;
214
+ res.json({
215
+ courseId,
216
+ strategyId,
217
+ periodStart,
218
+ periodEnd,
219
+ observations: scatterData.length,
220
+ data: scatterData,
221
+ regression: gradient,
222
+ });
223
+ }
224
+ catch (error) {
225
+ logger.error(`[Orchestration] Scatter plot error: ${error}`);
226
+ res.status(500).json({ error: 'Failed to get scatter data', details: String(error) });
227
+ }
228
+ })();
229
+ });
230
+ /**
231
+ * GET /orchestration/:courseId/weights
232
+ *
233
+ * Get current learned weights for all strategies in a course.
234
+ * Simpler alternative to /state endpoint - just returns weight/confidence without history.
235
+ */
236
+ router.get('/:courseId/weights', (req, res) => {
237
+ void (async () => {
238
+ try {
239
+ const { courseId } = req.params;
240
+ const courseDB = await useOrCreateCourseDB(courseId);
241
+ // Get all strategies
242
+ const strategiesResp = await courseDB.find({
243
+ selector: { docType: 'NAVIGATION_STRATEGY' },
244
+ });
245
+ const strategies = strategiesResp.docs;
246
+ const weights = strategies.map((strategy) => ({
247
+ strategyId: strategy._id,
248
+ strategyName: strategy.name,
249
+ implementingClass: strategy.implementingClass,
250
+ learnable: strategy.learnable || null,
251
+ staticWeight: strategy.staticWeight || false,
252
+ }));
253
+ res.json({
254
+ courseId,
255
+ weights,
256
+ });
257
+ }
258
+ catch (error) {
259
+ logger.error(`[Orchestration] Get weights error: ${error}`);
260
+ res.status(500).json({ error: 'Failed to get weights', details: String(error) });
261
+ }
262
+ })();
263
+ });
264
+ /**
265
+ * GET /orchestration/:courseId/strategy/:strategyId/distribution
266
+ *
267
+ * Get the current bell curve distribution for a strategy.
268
+ * Shows how users are distributed across weight space based on current confidence.
269
+ *
270
+ * Query params:
271
+ * - samples: number of sample points (default: 100)
272
+ */
273
+ router.get('/:courseId/strategy/:strategyId/distribution', (req, res) => {
274
+ void (async () => {
275
+ try {
276
+ const { courseId, strategyId } = req.params;
277
+ const samples = parseInt(req.query.samples || '100', 10);
278
+ const courseDB = await useOrCreateCourseDB(courseId);
279
+ // Get strategy
280
+ const strategy = (await courseDB.get(strategyId));
281
+ if (!strategy.learnable) {
282
+ res.json({
283
+ courseId,
284
+ strategyId,
285
+ message: 'Strategy does not have learnable weights',
286
+ distribution: null,
287
+ });
288
+ return;
289
+ }
290
+ const { weight, confidence } = strategy.learnable;
291
+ // Compute spread
292
+ const MIN_SPREAD = 0.1;
293
+ const MAX_SPREAD = 0.5;
294
+ const spread = MAX_SPREAD - confidence * (MAX_SPREAD - MIN_SPREAD);
295
+ // Generate distribution points
296
+ const distribution = [];
297
+ for (let i = 0; i < samples; i++) {
298
+ const deviation = -1 + (2 * i) / (samples - 1); // Range [-1, 1]
299
+ const effectiveWeight = Math.max(0.1, Math.min(3.0, weight + deviation * spread * weight));
300
+ // Gaussian density (unnormalized, for visualization)
301
+ const density = Math.exp(-0.5 * (deviation / 0.5) ** 2);
302
+ distribution.push({
303
+ deviation,
304
+ effectiveWeight,
305
+ density,
306
+ });
307
+ }
308
+ res.json({
309
+ courseId,
310
+ strategyId,
311
+ peakWeight: weight,
312
+ confidence,
313
+ spread,
314
+ distribution,
315
+ });
316
+ }
317
+ catch (error) {
318
+ logger.error(`[Orchestration] Distribution error: ${error}`);
319
+ res.status(500).json({ error: 'Failed to get distribution', details: String(error) });
320
+ }
321
+ })();
322
+ });
323
+ // ============================================================================
324
+ // HELPER FUNCTIONS
325
+ // ============================================================================
326
+ /**
327
+ * Aggregate user outcome records across all user databases.
328
+ *
329
+ * This is a server-side operation that requires admin access to query
330
+ * across user databases.
331
+ *
332
+ * TODO: Consider adding a view/index for more efficient querying.
333
+ */
334
+ async function aggregateUserOutcomes(courseId, periodStart, periodEnd) {
335
+ const couch = getCouchDB();
336
+ const outcomes = [];
337
+ try {
338
+ // Get list of all user databases
339
+ const allDbs = await couch.db.list();
340
+ const userDbs = allDbs.filter((db) => db.startsWith('userdb-'));
341
+ logger.debug(`[Orchestration] Scanning ${userDbs.length} user databases for outcomes`);
342
+ for (const dbName of userDbs) {
343
+ try {
344
+ const userDb = couch.use(dbName);
345
+ // Query for outcome records for this course in the time range
346
+ const result = await userDb.find({
347
+ selector: {
348
+ docType: 'USER_OUTCOME',
349
+ courseId,
350
+ periodEnd: {
351
+ $gte: periodStart,
352
+ $lte: periodEnd,
353
+ },
354
+ },
355
+ limit: 1000,
356
+ });
357
+ for (const doc of result.docs) {
358
+ outcomes.push(doc);
359
+ }
360
+ }
361
+ catch (e) {
362
+ // Skip databases that don't have the index or fail
363
+ logger.debug(`[Orchestration] Skipping ${dbName}: ${e}`);
364
+ }
365
+ }
366
+ return outcomes;
367
+ }
368
+ catch (error) {
369
+ logger.error(`[Orchestration] Error aggregating outcomes: ${error}`);
370
+ return [];
371
+ }
372
+ }
373
+ export default router;
374
+ //# sourceMappingURL=orchestration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestration.js","sourceRoot":"","sources":["../../src/routes/orchestration.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.22",
6
+ "version": "0.1.24",
7
7
  "description": "an API",
8
8
  "main": "dist/index.js",
9
9
  "type": "module",
@@ -35,8 +35,8 @@
35
35
  "author": "Colin Kennedy",
36
36
  "license": "GPL-3.0-or-later",
37
37
  "dependencies": {
38
- "@vue-skuilder/common": "^0.1.22",
39
- "@vue-skuilder/db": "^0.1.22",
38
+ "@vue-skuilder/common": "^0.1.24",
39
+ "@vue-skuilder/db": "^0.1.24",
40
40
  "axios": "^1.12.0",
41
41
  "cookie-parser": "^1.4.7",
42
42
  "cors": "^2.8.5",
@@ -77,5 +77,5 @@
77
77
  "typescript-eslint": "^8.48.1",
78
78
  "vitest": "^4.0.15"
79
79
  },
80
- "stableVersion": "0.1.22"
80
+ "stableVersion": "0.1.24"
81
81
  }
@@ -28,6 +28,7 @@ import { classroomDbDesignDoc } from './design-docs.js';
28
28
  import logger from './logger.js';
29
29
  import logsRouter from './routes/logs.js';
30
30
  import authRouter from './routes/auth.js';
31
+ import orchestrationRouter from './routes/orchestration.js';
31
32
  import type { ExpressServerConfig, EnvironmentConfig } from './types.js';
32
33
  import { applyUsersDesignDocs } from './couchdb/userDesignDocs.js';
33
34
 
@@ -94,6 +95,7 @@ export function createExpressApp(config: AppConfig): express.Application {
94
95
  );
95
96
  app.use('/logs', logsRouter);
96
97
  app.use('/auth', authRouter);
98
+ app.use('/orchestration', orchestrationRouter);
97
99
 
98
100
  // Routes
99
101
  app.get('/courses', (_req: Request, res: Response) => {
@@ -0,0 +1,443 @@
1
+ import { Router, Request, Response } from 'express';
2
+ import Nano from 'nano';
3
+ import { requestIsAuthenticated } from '../couchdb/authentication.js';
4
+ import { useOrCreateCourseDB, getCouchDB } from '../couchdb/index.js';
5
+ import logger from '../logger.js';
6
+ import {
7
+ aggregateOutcomesForGradient,
8
+ computeStrategyGradient,
9
+ runPeriodUpdate,
10
+ getDefaultLearnableWeight,
11
+ } from '@vue-skuilder/db';
12
+ import type {
13
+ UserOutcomeRecord,
14
+ StrategyLearningState,
15
+ PeriodUpdateInput,
16
+ } from '@vue-skuilder/db';
17
+ import type { ContentNavigationStrategyData } from '@vue-skuilder/db/core';
18
+
19
+ const router = Router();
20
+
21
+ /**
22
+ * POST /orchestration/:courseId/update
23
+ *
24
+ * Trigger a period update for all strategies in a course.
25
+ * This aggregates user outcomes and adjusts strategy weights based on gradients.
26
+ *
27
+ * Requires authentication.
28
+ *
29
+ * Query params:
30
+ * - periodStart: ISO timestamp (optional, defaults to 7 days ago)
31
+ * - periodEnd: ISO timestamp (optional, defaults to now)
32
+ */
33
+ router.post('/:courseId/update', (req: Request, res: Response) => {
34
+ void (async () => {
35
+ try {
36
+ const auth = await requestIsAuthenticated(req);
37
+ if (!auth) {
38
+ res.status(401).json({ error: 'Unauthorized' });
39
+ return;
40
+ }
41
+
42
+ const { courseId } = req.params;
43
+ const periodEnd = (req.query.periodEnd as string) || new Date().toISOString();
44
+ const periodStart =
45
+ (req.query.periodStart as string) ||
46
+ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
47
+
48
+ logger.info(
49
+ `[Orchestration] Period update requested for course ${courseId} ` +
50
+ `(${periodStart} to ${periodEnd})`
51
+ );
52
+
53
+ // 1. Get course DB and strategies
54
+ const courseDB = await useOrCreateCourseDB(courseId);
55
+ const strategiesResp = await courseDB.find({
56
+ selector: { docType: 'NAVIGATION_STRATEGY' },
57
+ });
58
+ const strategies = strategiesResp.docs as unknown as ContentNavigationStrategyData[];
59
+
60
+ if (strategies.length === 0) {
61
+ res.json({ message: 'No strategies found', updated: 0 });
62
+ return;
63
+ }
64
+
65
+ // 2. Aggregate user outcomes for this course
66
+ // Note: This queries across user DBs - requires admin access
67
+ const outcomes = await aggregateUserOutcomes(courseId, periodStart, periodEnd);
68
+
69
+ if (outcomes.length === 0) {
70
+ res.json({ message: 'No outcome records found', updated: 0 });
71
+ return;
72
+ }
73
+
74
+ logger.info(`[Orchestration] Found ${outcomes.length} outcome records for ${courseId}`);
75
+
76
+ // 3. Process each strategy
77
+ const results = [];
78
+
79
+ for (const strategy of strategies) {
80
+ const strategyId = strategy._id;
81
+
82
+ // Skip static weight strategies
83
+ if (strategy.staticWeight) {
84
+ logger.debug(`[Orchestration] Skipping static strategy ${strategyId}`);
85
+ continue;
86
+ }
87
+
88
+ // Get or create learning state
89
+ let existingState: StrategyLearningState | undefined;
90
+ try {
91
+ existingState = (await courseDB.get(
92
+ `STRATEGY_LEARNING_STATE::${courseId}::${strategyId}`
93
+ )) as unknown as StrategyLearningState;
94
+ } catch {
95
+ // No existing state, that's fine
96
+ }
97
+
98
+ // Aggregate observations for this strategy
99
+ const observations = aggregateOutcomesForGradient(outcomes, strategyId);
100
+
101
+ if (observations.length < 3) {
102
+ logger.debug(
103
+ `[Orchestration] Insufficient observations for ${strategyId} (${observations.length})`
104
+ );
105
+ continue;
106
+ }
107
+
108
+ // Compute gradient
109
+ const gradient = computeStrategyGradient(observations);
110
+ if (!gradient) {
111
+ continue;
112
+ }
113
+
114
+ // Get current weight
115
+ const currentWeight = strategy.learnable || getDefaultLearnableWeight();
116
+
117
+ // Run update
118
+ const input: PeriodUpdateInput = {
119
+ courseId,
120
+ strategyId,
121
+ currentWeight,
122
+ gradient,
123
+ existingState,
124
+ };
125
+
126
+ const result = runPeriodUpdate(input);
127
+
128
+ // Persist updated strategy
129
+ if (result.updated) {
130
+ const updatedStrategy = {
131
+ ...strategy,
132
+ learnable: result.newWeight,
133
+ };
134
+ await courseDB.insert(updatedStrategy as unknown as Nano.MaybeDocument);
135
+ }
136
+
137
+ // Persist learning state
138
+ await courseDB.insert(result.learningState as unknown as Nano.MaybeDocument);
139
+
140
+ results.push({
141
+ strategyId,
142
+ previousWeight: result.previousWeight.weight,
143
+ newWeight: result.newWeight.weight,
144
+ gradient: gradient.gradient,
145
+ rSquared: gradient.rSquared,
146
+ observations: observations.length,
147
+ });
148
+ }
149
+
150
+ res.json({
151
+ message: 'Period update complete',
152
+ courseId,
153
+ periodStart,
154
+ periodEnd,
155
+ outcomesProcessed: outcomes.length,
156
+ strategiesUpdated: results.filter((r) => r.previousWeight !== r.newWeight).length,
157
+ results,
158
+ });
159
+ } catch (error) {
160
+ logger.error(`[Orchestration] Period update error: ${error}`);
161
+ res.status(500).json({ error: 'Period update failed', details: String(error) });
162
+ }
163
+ })();
164
+ });
165
+
166
+ /**
167
+ * GET /orchestration/:courseId/state
168
+ *
169
+ * Get current learning state for all strategies in a course.
170
+ */
171
+ router.get('/:courseId/state', (req: Request, res: Response) => {
172
+ void (async () => {
173
+ try {
174
+ const { courseId } = req.params;
175
+ const courseDB = await useOrCreateCourseDB(courseId);
176
+
177
+ const statesResp = await courseDB.find({
178
+ selector: { docType: 'STRATEGY_LEARNING_STATE' },
179
+ });
180
+
181
+ res.json({
182
+ courseId,
183
+ states: statesResp.docs,
184
+ });
185
+ } catch (error) {
186
+ logger.error(`[Orchestration] Get state error: ${error}`);
187
+ res.status(500).json({ error: 'Failed to get state', details: String(error) });
188
+ }
189
+ })();
190
+ });
191
+
192
+ /**
193
+ * GET /orchestration/:courseId/strategy/:strategyId/history
194
+ *
195
+ * Get weight history for a specific strategy.
196
+ */
197
+ router.get('/:courseId/strategy/:strategyId/history', (req: Request, res: Response) => {
198
+ void (async () => {
199
+ try {
200
+ const { courseId, strategyId } = req.params;
201
+ const courseDB = await useOrCreateCourseDB(courseId);
202
+
203
+ const stateId = `STRATEGY_LEARNING_STATE::${courseId}::${strategyId}`;
204
+
205
+ try {
206
+ const state = (await courseDB.get(stateId)) as StrategyLearningState;
207
+ res.json({
208
+ courseId,
209
+ strategyId,
210
+ currentWeight: state.currentWeight,
211
+ regression: state.regression,
212
+ history: state.history,
213
+ });
214
+ } catch {
215
+ res.status(404).json({ error: 'No learning state found for this strategy' });
216
+ }
217
+ } catch (error) {
218
+ logger.error(`[Orchestration] Get history error: ${error}`);
219
+ res.status(500).json({ error: 'Failed to get history', details: String(error) });
220
+ }
221
+ })();
222
+ });
223
+
224
+ /**
225
+ * GET /orchestration/:courseId/strategy/:strategyId/scatter
226
+ *
227
+ * Get scatter plot data (deviation vs outcome) for a specific strategy.
228
+ * Useful for visualizing the gradient and understanding the learning dynamics.
229
+ *
230
+ * Query params:
231
+ * - periodStart: ISO timestamp (optional, defaults to 7 days ago)
232
+ * - periodEnd: ISO timestamp (optional, defaults to now)
233
+ * - limit: max observations to return (optional, defaults to 1000)
234
+ */
235
+ router.get('/:courseId/strategy/:strategyId/scatter', (req: Request, res: Response) => {
236
+ void (async () => {
237
+ try {
238
+ const { courseId, strategyId } = req.params;
239
+ const periodEnd = (req.query.periodEnd as string) || new Date().toISOString();
240
+ const periodStart =
241
+ (req.query.periodStart as string) ||
242
+ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
243
+ const limit = parseInt((req.query.limit as string) || '1000', 10);
244
+
245
+ // Aggregate outcomes
246
+ const outcomes = await aggregateUserOutcomes(courseId, periodStart, periodEnd);
247
+
248
+ // Extract scatter data for this strategy
249
+ const scatterData = outcomes
250
+ .filter((outcome) => outcome.deviations[strategyId] !== undefined)
251
+ .map((outcome) => ({
252
+ deviation: outcome.deviations[strategyId],
253
+ outcome: outcome.outcomeValue,
254
+ userId: outcome.userId,
255
+ periodEnd: outcome.periodEnd,
256
+ }))
257
+ .slice(0, limit);
258
+
259
+ // Compute regression for visualization
260
+ const observations = aggregateOutcomesForGradient(outcomes, strategyId);
261
+ const gradient = observations.length >= 3 ? computeStrategyGradient(observations) : null;
262
+
263
+ res.json({
264
+ courseId,
265
+ strategyId,
266
+ periodStart,
267
+ periodEnd,
268
+ observations: scatterData.length,
269
+ data: scatterData,
270
+ regression: gradient,
271
+ });
272
+ } catch (error) {
273
+ logger.error(`[Orchestration] Scatter plot error: ${error}`);
274
+ res.status(500).json({ error: 'Failed to get scatter data', details: String(error) });
275
+ }
276
+ })();
277
+ });
278
+
279
+ /**
280
+ * GET /orchestration/:courseId/weights
281
+ *
282
+ * Get current learned weights for all strategies in a course.
283
+ * Simpler alternative to /state endpoint - just returns weight/confidence without history.
284
+ */
285
+ router.get('/:courseId/weights', (req: Request, res: Response) => {
286
+ void (async () => {
287
+ try {
288
+ const { courseId } = req.params;
289
+ const courseDB = await useOrCreateCourseDB(courseId);
290
+
291
+ // Get all strategies
292
+ const strategiesResp = await courseDB.find({
293
+ selector: { docType: 'NAVIGATION_STRATEGY' },
294
+ });
295
+ const strategies = strategiesResp.docs as unknown as ContentNavigationStrategyData[];
296
+
297
+ const weights = strategies.map((strategy) => ({
298
+ strategyId: strategy._id,
299
+ strategyName: strategy.name,
300
+ implementingClass: strategy.implementingClass,
301
+ learnable: strategy.learnable || null,
302
+ staticWeight: strategy.staticWeight || false,
303
+ }));
304
+
305
+ res.json({
306
+ courseId,
307
+ weights,
308
+ });
309
+ } catch (error) {
310
+ logger.error(`[Orchestration] Get weights error: ${error}`);
311
+ res.status(500).json({ error: 'Failed to get weights', details: String(error) });
312
+ }
313
+ })();
314
+ });
315
+
316
+ /**
317
+ * GET /orchestration/:courseId/strategy/:strategyId/distribution
318
+ *
319
+ * Get the current bell curve distribution for a strategy.
320
+ * Shows how users are distributed across weight space based on current confidence.
321
+ *
322
+ * Query params:
323
+ * - samples: number of sample points (default: 100)
324
+ */
325
+ router.get('/:courseId/strategy/:strategyId/distribution', (req: Request, res: Response) => {
326
+ void (async () => {
327
+ try {
328
+ const { courseId, strategyId } = req.params;
329
+ const samples = parseInt((req.query.samples as string) || '100', 10);
330
+ const courseDB = await useOrCreateCourseDB(courseId);
331
+
332
+ // Get strategy
333
+ const strategy = (await courseDB.get(strategyId)) as unknown as ContentNavigationStrategyData;
334
+
335
+ if (!strategy.learnable) {
336
+ res.json({
337
+ courseId,
338
+ strategyId,
339
+ message: 'Strategy does not have learnable weights',
340
+ distribution: null,
341
+ });
342
+ return;
343
+ }
344
+
345
+ const { weight, confidence } = strategy.learnable;
346
+
347
+ // Compute spread
348
+ const MIN_SPREAD = 0.1;
349
+ const MAX_SPREAD = 0.5;
350
+ const spread = MAX_SPREAD - confidence * (MAX_SPREAD - MIN_SPREAD);
351
+
352
+ // Generate distribution points
353
+ const distribution = [];
354
+ for (let i = 0; i < samples; i++) {
355
+ const deviation = -1 + (2 * i) / (samples - 1); // Range [-1, 1]
356
+ const effectiveWeight = Math.max(0.1, Math.min(3.0, weight + deviation * spread * weight));
357
+
358
+ // Gaussian density (unnormalized, for visualization)
359
+ const density = Math.exp(-0.5 * (deviation / 0.5) ** 2);
360
+
361
+ distribution.push({
362
+ deviation,
363
+ effectiveWeight,
364
+ density,
365
+ });
366
+ }
367
+
368
+ res.json({
369
+ courseId,
370
+ strategyId,
371
+ peakWeight: weight,
372
+ confidence,
373
+ spread,
374
+ distribution,
375
+ });
376
+ } catch (error) {
377
+ logger.error(`[Orchestration] Distribution error: ${error}`);
378
+ res.status(500).json({ error: 'Failed to get distribution', details: String(error) });
379
+ }
380
+ })();
381
+ });
382
+
383
+ // ============================================================================
384
+ // HELPER FUNCTIONS
385
+ // ============================================================================
386
+
387
+ /**
388
+ * Aggregate user outcome records across all user databases.
389
+ *
390
+ * This is a server-side operation that requires admin access to query
391
+ * across user databases.
392
+ *
393
+ * TODO: Consider adding a view/index for more efficient querying.
394
+ */
395
+ async function aggregateUserOutcomes(
396
+ courseId: string,
397
+ periodStart: string,
398
+ periodEnd: string
399
+ ): Promise<UserOutcomeRecord[]> {
400
+ const couch = getCouchDB();
401
+ const outcomes: UserOutcomeRecord[] = [];
402
+
403
+ try {
404
+ // Get list of all user databases
405
+ const allDbs = await couch.db.list();
406
+ const userDbs = allDbs.filter((db) => db.startsWith('userdb-'));
407
+
408
+ logger.debug(`[Orchestration] Scanning ${userDbs.length} user databases for outcomes`);
409
+
410
+ for (const dbName of userDbs) {
411
+ try {
412
+ const userDb = couch.use(dbName);
413
+
414
+ // Query for outcome records for this course in the time range
415
+ const result = await userDb.find({
416
+ selector: {
417
+ docType: 'USER_OUTCOME',
418
+ courseId,
419
+ periodEnd: {
420
+ $gte: periodStart,
421
+ $lte: periodEnd,
422
+ },
423
+ },
424
+ limit: 1000,
425
+ });
426
+
427
+ for (const doc of result.docs) {
428
+ outcomes.push(doc as unknown as UserOutcomeRecord);
429
+ }
430
+ } catch (e) {
431
+ // Skip databases that don't have the index or fail
432
+ logger.debug(`[Orchestration] Skipping ${dbName}: ${e}`);
433
+ }
434
+ }
435
+
436
+ return outcomes;
437
+ } catch (error) {
438
+ logger.error(`[Orchestration] Error aggregating outcomes: ${error}`);
439
+ return [];
440
+ }
441
+ }
442
+
443
+ export default router;