@vue-skuilder/db 0.1.23 → 0.1.25

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.
Files changed (80) hide show
  1. package/dist/{contentSource-BP9hznNV.d.ts → contentSource-BmnmvH8C.d.ts} +268 -3
  2. package/dist/{contentSource-DsJadoBU.d.cts → contentSource-DfBbaLA-.d.cts} +268 -3
  3. package/dist/core/index.d.cts +310 -6
  4. package/dist/core/index.d.ts +310 -6
  5. package/dist/core/index.js +2606 -666
  6. package/dist/core/index.js.map +1 -1
  7. package/dist/core/index.mjs +2564 -639
  8. package/dist/core/index.mjs.map +1 -1
  9. package/dist/{dataLayerProvider-CHYrQ5pB.d.cts → dataLayerProvider-BeRXVMs5.d.cts} +1 -1
  10. package/dist/{dataLayerProvider-MDTxXq2l.d.ts → dataLayerProvider-CG9GfaAY.d.ts} +1 -1
  11. package/dist/impl/couch/index.d.cts +11 -3
  12. package/dist/impl/couch/index.d.ts +11 -3
  13. package/dist/impl/couch/index.js +2336 -656
  14. package/dist/impl/couch/index.js.map +1 -1
  15. package/dist/impl/couch/index.mjs +2316 -631
  16. package/dist/impl/couch/index.mjs.map +1 -1
  17. package/dist/impl/static/index.d.cts +4 -4
  18. package/dist/impl/static/index.d.ts +4 -4
  19. package/dist/impl/static/index.js +2312 -632
  20. package/dist/impl/static/index.js.map +1 -1
  21. package/dist/impl/static/index.mjs +2315 -630
  22. package/dist/impl/static/index.mjs.map +1 -1
  23. package/dist/{index-Dj0SEgk3.d.ts → index-BWvO-_rJ.d.ts} +1 -1
  24. package/dist/{index-B_j6u5E4.d.cts → index-Ba7hYbHj.d.cts} +1 -1
  25. package/dist/index.d.cts +278 -20
  26. package/dist/index.d.ts +278 -20
  27. package/dist/index.js +3603 -720
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +3529 -674
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/{types-DQaXnuoc.d.ts → types-CJrLM1Ew.d.ts} +1 -1
  32. package/dist/{types-Bn0itutr.d.cts → types-W8n-B6HG.d.cts} +1 -1
  33. package/dist/{types-legacy-DDY4N-Uq.d.cts → types-legacy-JXDxinpU.d.cts} +5 -1
  34. package/dist/{types-legacy-DDY4N-Uq.d.ts → types-legacy-JXDxinpU.d.ts} +5 -1
  35. package/dist/util/packer/index.d.cts +3 -3
  36. package/dist/util/packer/index.d.ts +3 -3
  37. package/docs/brainstorm-navigation-paradigm.md +40 -34
  38. package/docs/future-orchestration-vision.md +216 -0
  39. package/docs/navigators-architecture.md +210 -9
  40. package/docs/todo-review-urgency-adaptation.md +205 -0
  41. package/docs/todo-strategy-authoring.md +8 -6
  42. package/package.json +3 -3
  43. package/src/core/index.ts +2 -0
  44. package/src/core/interfaces/contentSource.ts +7 -0
  45. package/src/core/interfaces/userDB.ts +50 -0
  46. package/src/core/navigators/Pipeline.ts +132 -5
  47. package/src/core/navigators/PipelineAssembler.ts +21 -22
  48. package/src/core/navigators/PipelineDebugger.ts +426 -0
  49. package/src/core/navigators/filters/WeightedFilter.ts +141 -0
  50. package/src/core/navigators/filters/types.ts +4 -0
  51. package/src/core/navigators/generators/CompositeGenerator.ts +82 -19
  52. package/src/core/navigators/generators/elo.ts +14 -1
  53. package/src/core/navigators/generators/srs.ts +146 -18
  54. package/src/core/navigators/generators/types.ts +4 -0
  55. package/src/core/navigators/index.ts +203 -13
  56. package/src/core/orchestration/gradient.ts +133 -0
  57. package/src/core/orchestration/index.ts +210 -0
  58. package/src/core/orchestration/learning.ts +250 -0
  59. package/src/core/orchestration/recording.ts +92 -0
  60. package/src/core/orchestration/signal.ts +67 -0
  61. package/src/core/types/contentNavigationStrategy.ts +38 -0
  62. package/src/core/types/learningState.ts +77 -0
  63. package/src/core/types/types-legacy.ts +4 -0
  64. package/src/core/types/userOutcome.ts +51 -0
  65. package/src/courseConfigRegistration.ts +107 -0
  66. package/src/factory.ts +6 -0
  67. package/src/impl/common/BaseUserDB.ts +16 -0
  68. package/src/impl/couch/user-course-relDB.ts +12 -0
  69. package/src/study/MixerDebugger.ts +555 -0
  70. package/src/study/SessionController.ts +159 -20
  71. package/src/study/SessionDebugger.ts +442 -0
  72. package/src/study/SourceMixer.ts +36 -17
  73. package/src/study/TODO-session-scheduling.md +133 -0
  74. package/src/study/index.ts +2 -0
  75. package/src/study/services/EloService.ts +79 -4
  76. package/src/study/services/ResponseProcessor.ts +130 -72
  77. package/src/study/services/SrsService.ts +9 -0
  78. package/tests/core/navigators/Pipeline.test.ts +2 -0
  79. package/tests/core/navigators/PipelineAssembler.test.ts +4 -4
  80. package/docs/todo-evolutionary-orchestration.md +0 -310
@@ -5,6 +5,9 @@
5
5
  The navigation strategy system selects and scores cards for study sessions. It uses a
6
6
  **Pipeline architecture** where generators produce candidates and filters transform scores.
7
7
 
8
+ An **Evolutionary Orchestration** layer enables strategies to carry learnable weights that
9
+ automatically tune toward optimal values based on observed learning outcomes.
10
+
8
11
  ## Core Concepts
9
12
 
10
13
  ### WeightedCard
@@ -27,6 +30,7 @@ interface StrategyContribution {
27
30
  action: 'generated' | 'passed' | 'boosted' | 'penalized';
28
31
  score: number; // Score after this strategy
29
32
  reason: string; // Human-readable explanation
33
+ deviation?: number; // User's deviation from peak weight (evolutionary)
30
34
  }
31
35
  ```
32
36
 
@@ -42,11 +46,28 @@ interface CardGenerator {
42
46
  ```
43
47
 
44
48
  **Implementations:**
45
- - `ELONavigator` — New cards scored by ELO proximity to user skill
46
- - `SRSNavigator` — Review cards scored by overdueness and interval recency
49
+ - `ELONavigator` — New cards scored by ELO proximity to user skill (scores 0.0-1.0)
50
+ - `SRSNavigator` — Review cards scored by overdueness, interval recency, and **backlog pressure** (scores 0.5-1.0)
47
51
  - `HardcodedOrderNavigator` — Fixed sequence defined by course author
48
52
  - `CompositeGenerator` — Merges multiple generators with frequency boost
49
53
 
54
+ #### SRS Backlog Pressure
55
+
56
+ The SRS generator implements a self-regulating **backlog pressure** mechanism that prevents review pile-up while maintaining healthy new/review balance:
57
+
58
+ - **Healthy backlog** (≤20 due reviews): No pressure boost, scores 0.5-0.95. New content (ELO) naturally dominates.
59
+ - **Elevated backlog** (40 due): +0.25 boost, scores 0.75-1.0. Reviews compete with new cards.
60
+ - **High backlog** (60+ due): +0.50 boost (max), scores 0.95-1.0. Reviews take priority.
61
+
62
+ This treats SRS scheduling times as **eligibility dates** rather than hard due dates—reviewing slightly later may be optimal. The system maintains a healthy backlog rather than always clearing to zero (avoiding "Anki death spiral").
63
+
64
+ Configuration via strategy `serializedData`:
65
+ ```json
66
+ { "healthyBacklog": 20 }
67
+ ```
68
+
69
+ See `todo-review-adaptation.md` for planned per-user adaptation extensions.
70
+
50
71
  ### CardFilter
51
72
 
52
73
  Transforms card scores (pure function, no side effects):
@@ -82,7 +103,7 @@ class Pipeline {
82
103
  )
83
104
 
84
105
  async getWeightedCards(limit: number): Promise<WeightedCard[]> {
85
- // Build shared context (user ELO, etc.)
106
+ // Build shared context (user ELO, orchestration context, etc.)
86
107
  const context = await this.buildContext();
87
108
 
88
109
  // Generate candidates
@@ -104,7 +125,7 @@ class Pipeline {
104
125
  ```
105
126
 
106
127
  **Responsibilities:**
107
- - **Context building** — Fetches shared data (user ELO) once for all strategies
128
+ - **Context building** — Fetches shared data (user ELO, orchestration context) once for all strategies
108
129
  - **Data hydration** — Pre-fetches commonly needed data (tags) in batch queries
109
130
  - **Filter orchestration** — Applies filters in sequence, accumulating provenance
110
131
  - **Result selection** — Removes zero-scores, sorts, and returns top N
@@ -170,7 +191,8 @@ provenance: [
170
191
  strategyId: 'NAVIGATION_STRATEGY-hierarchy-phonics',
171
192
  action: 'passed',
172
193
  score: 0.85,
173
- reason: 'Prerequisites met, tags: letter-sounds'
194
+ reason: 'Prerequisites met, tags: letter-sounds',
195
+ deviation: 0.23 // User's position on bell curve for this strategy
174
196
  },
175
197
  {
176
198
  strategy: 'eloDistance',
@@ -185,6 +207,171 @@ provenance: [
185
207
 
186
208
  Use `getCardOrigin(card)` to extract 'new', 'review', or 'failed' from provenance.
187
209
 
210
+ ---
211
+
212
+ ## Evolutionary Orchestration
213
+
214
+ The orchestration layer enables strategies to **learn optimal weights** from observed
215
+ learning outcomes. Instead of fixed configuration, strategies carry **learnable weights**
216
+ that automatically tune toward effectiveness.
217
+
218
+ ### LearnableWeight
219
+
220
+ Every strategy can carry a learnable weight:
221
+
222
+ ```typescript
223
+ interface LearnableWeight {
224
+ weight: number; // Peak value, 1.0 = neutral, range [0.1, 3.0]
225
+ confidence: number; // 0-1, controls exploration width
226
+ sampleSize: number; // Total observations for this strategy
227
+
228
+ history?: Array<{ // Optional: for visualization
229
+ timestamp: string;
230
+ weight: number;
231
+ confidence: number;
232
+ gradient: number;
233
+ }>;
234
+ }
235
+ ```
236
+
237
+ Strategies extend with:
238
+
239
+ ```typescript
240
+ interface ContentNavigationStrategyData {
241
+ // ... existing fields ...
242
+ learnable?: LearnableWeight; // Omitted = default weight 1.0
243
+ staticWeight?: boolean; // If true, not subject to learning
244
+ }
245
+ ```
246
+
247
+ ### Deviation-Based Weight Distribution
248
+
249
+ Each user experiences a **stable deviation** from the peak weight:
250
+
251
+ ```
252
+ effectiveWeight(user, strategy) = peakWeight + deviation * spread
253
+
254
+ where:
255
+ deviation = hash(userId, strategyId, salt) → [-1, 1] // stable per user
256
+ spread = max(MIN_SPREAD, (1 - confidence) * MAX_SPREAD)
257
+ ```
258
+
259
+ **Key insight:** Deviation is constant for a user. As confidence grows and spread
260
+ shrinks, all users are pulled toward the optimal peak.
261
+
262
+ ```typescript
263
+ // Example: Low confidence = wide exploration
264
+ { weight: 1.0, confidence: 0.2 }
265
+ → spread = 0.8 * MAX_SPREAD
266
+ → users range from weight 0.6 to 1.4
267
+
268
+ // Example: High confidence = narrow convergence
269
+ { weight: 1.2, confidence: 0.9 }
270
+ → spread = 0.1 * MAX_SPREAD
271
+ → users cluster around weight 1.15 to 1.25
272
+ ```
273
+
274
+ ### Outcome Recording
275
+
276
+ At the end of each learning period, user outcomes are recorded:
277
+
278
+ ```typescript
279
+ interface UserOutcomeRecord {
280
+ _id: `USER_OUTCOME::${courseId}::${periodId}`;
281
+ docType: DocType.USER_OUTCOME;
282
+ userId: string;
283
+ courseId: string;
284
+ periodStart: string;
285
+ periodEnd: string;
286
+ strategyExposures: Array<{
287
+ strategyId: string;
288
+ deviation: number; // User's stable deviation for this strategy
289
+ }>;
290
+ outcomeValue: number; // 0-1 learning outcome signal
291
+ }
292
+ ```
293
+
294
+ The outcome signal combines multiple factors:
295
+ - Accuracy within target zone (not too easy, not too hard)
296
+ - ELO progression
297
+ - Session completion
298
+
299
+ ### Gradient Learning
300
+
301
+ The system discovers optimal weights by correlating **deviation with outcomes**
302
+ across users:
303
+
304
+ ```
305
+ +deviation → +outcome = positive gradient → increase peak weight
306
+ +deviation → -outcome = negative gradient → decrease peak weight
307
+ flat gradient = at optimum, increase confidence
308
+ ```
309
+
310
+ Linear regression on (deviation, outcome) pairs produces:
311
+ - **Gradient**: Direction to adjust peak
312
+ - **R²**: Signal quality (high = consistent effect)
313
+ - **Sample size**: Update confidence
314
+
315
+ ### Weight Update Cycle
316
+
317
+ Periodically (or on-demand), the system updates strategy weights:
318
+
319
+ ```typescript
320
+ async function runPeriodUpdate(courseId: string): Promise<void> {
321
+ for (const strategy of await getLearnableStrategies(courseId)) {
322
+ const observations = await aggregateOutcomesForGradient(strategy);
323
+ const { gradient, rSquared } = computeStrategyGradient(observations);
324
+ await updateStrategyWeight(strategy, gradient, rSquared);
325
+ }
326
+ }
327
+ ```
328
+
329
+ **Update rules:**
330
+ - Positive gradient → increase peak weight
331
+ - Negative gradient → decrease peak weight
332
+ - Consistent observations → increase confidence
333
+ - Noisy observations → decrease confidence
334
+
335
+ ### Observability
336
+
337
+ The orchestration layer exposes API endpoints for monitoring:
338
+
339
+ | Endpoint | Purpose |
340
+ |----------|---------|
341
+ | `GET /orchestration/:courseId/state` | All learning states |
342
+ | `GET /orchestration/:courseId/weights` | Current weights summary |
343
+ | `GET /orchestration/:courseId/strategy/:id/history` | Weight trajectory over time |
344
+ | `GET /orchestration/:courseId/strategy/:id/scatter` | Deviation vs outcome data |
345
+ | `GET /orchestration/:courseId/strategy/:id/distribution` | Bell curve visualization |
346
+ | `POST /orchestration/:courseId/update` | Trigger period update |
347
+
348
+ An admin dashboard in platform-ui visualizes strategy weights, confidence,
349
+ gradient direction, and historical trajectories.
350
+
351
+ ### Lifecycle
352
+
353
+ ```
354
+ New strategy: Low confidence → wide spread → noisy gradient → big adjustments
355
+ Learning: Gradient visible → peak drifts → confidence grows → spread shrinks
356
+ Converged: High confidence → minimum spread → flat gradient → stable
357
+ Disturbed: Gradient reappears → peak drifts → adapts to new optimal
358
+ ```
359
+
360
+ ### Static vs Learnable
361
+
362
+ Set `staticWeight: true` for foundational strategies that should not be tuned:
363
+
364
+ ```typescript
365
+ {
366
+ strategyType: 'hierarchyDefinition',
367
+ name: 'Core Prerequisites',
368
+ staticWeight: true, // Never tuned by orchestration
369
+ // learnable field ignored
370
+ }
371
+ ```
372
+
373
+ ---
374
+
188
375
  ## Creating New Strategies
189
376
 
190
377
  ### Generator
@@ -249,6 +436,8 @@ class MyFilter extends ContentNavigator implements CardFilter {
249
436
 
250
437
  Register in `NavigatorRoles` as `NavigatorRole.FILTER`.
251
438
 
439
+ ---
440
+
252
441
  ## Strategy State Storage
253
442
 
254
443
  Strategies can persist user-scoped state (preferences, learned patterns, temporal tracking)
@@ -294,7 +483,7 @@ interface StrategyStateDoc<T> {
294
483
  courseId: string;
295
484
  strategyKey: string;
296
485
  data: T; // Strategy-specific payload
297
- updatedAt: string; // ISO timestamp
486
+ updatedAt: string;
298
487
  }
299
488
  ```
300
489
 
@@ -332,6 +521,8 @@ return { ...card, score: card.score * multiplier };
332
521
  - All sliders share global max for consistent visual comparison
333
522
  - Writes to strategy state via `userDB.putStrategyState()`
334
523
 
524
+ ---
525
+
335
526
  ## File Reference
336
527
 
337
528
  | File | Purpose |
@@ -342,8 +533,8 @@ return { ...card, score: card.score * multiplier };
342
533
  | `core/navigators/Pipeline.ts` | Pipeline orchestration |
343
534
  | `core/navigators/PipelineAssembler.ts` | Builds Pipeline from strategy docs |
344
535
  | `core/navigators/CompositeGenerator.ts` | Merges multiple generators |
345
- | `core/navigators/elo.ts` | ELO generator |
346
- | `core/navigators/srs.ts` | SRS generator |
536
+ | `core/navigators/generators/elo.ts` | ELO generator |
537
+ | `core/navigators/generators/srs.ts` | SRS generator (with backlog pressure) |
347
538
  | `core/navigators/hardcodedOrder.ts` | Fixed-order generator |
348
539
  | `core/navigators/hierarchyDefinition.ts` | Prerequisite filter |
349
540
  | `core/navigators/interferenceMitigator.ts` | Interference filter |
@@ -355,9 +546,19 @@ return { ...card, score: card.score * multiplier };
355
546
  | `core/navigators/inferredPreference.ts` | Inferred preference navigator (stub) |
356
547
  | `core/types/strategyState.ts` | `StrategyStateDoc`, `StrategyStateId` |
357
548
  | `impl/couch/courseDB.ts` | `createNavigator()` entry point |
549
+ | `core/orchestration/index.ts` | OrchestrationContext, deviation logic |
550
+ | `core/orchestration/gradient.ts` | Gradient computation |
551
+ | `core/orchestration/learning.ts` | Weight updates, period orchestration |
552
+ | `core/orchestration/signal.ts` | Outcome signal computation |
553
+ | `core/orchestration/recording.ts` | User outcome recording |
554
+ | `core/types/learningState.ts` | `StrategyLearningState` |
555
+ | `core/types/userOutcome.ts` | `UserOutcomeRecord` |
556
+ | `express/routes/orchestration.ts` | Observability API endpoints |
358
557
 
359
558
  ## Related Documentation
360
559
 
361
560
  - `todo-strategy-authoring.md` — UX and DX for authoring strategies
362
- - `todo-evolutionary-orchestration.md` — Long-term adaptive strategy vision
561
+ - `todo-review-adaptation.md` — Planned per-user review urgency adaptation
562
+ - `future-orchestration-vision.md` — Long-term adaptive strategy vision (beyond current implementation)
363
563
  - `devlog/1004` — Implementation details for tag hydration optimization
564
+ - `devlog/1032-orchestrator` — Evolutionary orchestration implementation details
@@ -0,0 +1,205 @@
1
+ # Future Work: Dynamic Review Urgency Adaptation
2
+
3
+ This document outlines planned extensions to the SRS backlog pressure system for adaptive review urgency tuning.
4
+
5
+ ## Background
6
+
7
+ The SRS generator now implements **backlog pressure** — a mechanism that boosts review urgency when the number of due reviews exceeds a "healthy" threshold (default: 20). This ensures reviews don't pile up indefinitely while maintaining a healthy mix of new and review content.
8
+
9
+ See implementation: `core/navigators/generators/srs.ts`
10
+
11
+ This document describes two extension directions:
12
+ 1. **Global/Orchestration Layer** — Course-wide tuning via learnable weights
13
+ 2. **Per-User Adaptation** — Individual urgency multipliers based on review outcomes
14
+
15
+ ---
16
+
17
+ ## Extension 1: Orchestrator-Tuned Generator Weights
18
+
19
+ ### Current State
20
+
21
+ The orchestration layer (`core/orchestration/`) already supports learnable weights:
22
+
23
+ ```typescript
24
+ interface LearnableWeight {
25
+ weight: number; // Peak value, 1.0 = neutral
26
+ confidence: number; // 0-1, controls exploration width
27
+ sampleSize: number; // Observations collected
28
+ }
29
+ ```
30
+
31
+ When a strategy has `learnable` set and `staticWeight: false`, the orchestrator:
32
+ 1. Distributes users across a weight range (bell curve around peak)
33
+ 2. Records learning outcomes per user
34
+ 3. Correlates user deviation with outcomes via gradient estimation
35
+ 4. Updates peak weight toward observed optimum
36
+
37
+ ### Application to Review Balance
38
+
39
+ The orchestrator can tune the ELO vs SRS balance by experimenting with their weights.
40
+
41
+ In `CompositeGenerator.getWeightedCards()`, weights are already applied:
42
+
43
+ ```typescript
44
+ let weight = gen.learnable?.weight ?? 1.0;
45
+ if (gen.learnable && !gen.staticWeight && context.orchestration) {
46
+ weight = context.orchestration.getEffectiveWeight(strategyId, gen.learnable);
47
+ }
48
+ ```
49
+
50
+ If SRS has `learnable: { weight: 1.0, confidence: 0.5, sampleSize: 0 }`, the orchestrator will try variations (0.8, 1.2, etc.) and correlate with learning outcomes.
51
+
52
+ ### Required Work
53
+
54
+ - [ ] Ensure default ELO and SRS strategy documents include `learnable` config
55
+ - [ ] Verify outcome correlation tracks success/failure per card source (generator provenance)
56
+ - [ ] Consider weight bounds (e.g., SRS weight ∈ [0.5, 2.0]) to prevent extreme tuning
57
+ - [ ] Test interaction with backlog pressure — may need to mark backlog-pressure-derived scores as non-learnable
58
+
59
+ ### Risks
60
+
61
+ - Orchestrator experiments could override backlog pressure intent
62
+ - May need to separate "base urgency" (learnable) from "backlog pressure" (not learnable)
63
+
64
+ ### Priority
65
+
66
+ **Low** — The backlog pressure mechanism should handle balance well. Orchestrator tuning is a refinement layer that can be enabled later.
67
+
68
+ ---
69
+
70
+ ## Extension 2: Per-User Review Urgency Adaptation
71
+
72
+ ### Concept
73
+
74
+ Users have different memory characteristics. A "forgetful" user needs more review pressure; a "retentive" user needs less. Rather than one-size-fits-all, maintain a per-user `reviewUrgencyMultiplier` that adapts based on review outcomes.
75
+
76
+ ### Proposed Data Model
77
+
78
+ ```typescript
79
+ interface ReviewAdaptationState {
80
+ urgencyMultiplier: number; // Default 1.0, range [0.5, 2.0]
81
+ windowStart: string; // ISO timestamp for rolling window
82
+ windowFailures: number; // Failures in current window
83
+ windowSuccesses: number; // Successes in current window
84
+ lastUpdated: string; // ISO timestamp
85
+ }
86
+ ```
87
+
88
+ ### Update Rules
89
+
90
+ - On failed review: `multiplier = min(2.0, multiplier + 0.05)`
91
+ - On successful review: `multiplier = max(0.5, multiplier - 0.01)`
92
+
93
+ **Asymmetry rationale**:
94
+ - Failures increase pressure quickly (5x faster than decrease)
95
+ - Successes slowly reduce pressure (avoid death spiral from one good session)
96
+
97
+ ### Equilibrium Analysis
98
+
99
+ At equilibrium: `0.05 * failRate = 0.01 * (1 - failRate)`
100
+
101
+ Solving: `failRate = 0.167` (16.7%)
102
+
103
+ This means:
104
+ - User with 16.7% failure rate → multiplier stable
105
+ - User with >16.7% failure rate → multiplier increases (more review pressure)
106
+ - User with <16.7% failure rate → multiplier decreases (less review pressure)
107
+
108
+ The equilibrium threshold can be tuned by adjusting increment/decrement rates.
109
+
110
+ ### Application in Scoring
111
+
112
+ In SRS urgency calculation:
113
+
114
+ ```typescript
115
+ const userAdaptation = await this.getReviewAdaptation();
116
+ const adaptedUrgency = baseUrgency * userAdaptation.urgencyMultiplier;
117
+ const score = Math.min(1.0, 0.5 + adaptedUrgency * 0.45 + backlogPressure);
118
+ ```
119
+
120
+ Note: multiplier affects base urgency, not backlog pressure. This preserves the global backlog escape mechanism.
121
+
122
+ ### Storage
123
+
124
+ Use strategy state storage (per-user, per-course, per-strategy):
125
+
126
+ ```typescript
127
+ const state = await this.getStrategyState<ReviewAdaptationState>();
128
+ await this.putStrategyState({ ...state, urgencyMultiplier: newValue });
129
+ ```
130
+
131
+ ### Implementation Sketch
132
+
133
+ ```typescript
134
+ // In srs.ts
135
+
136
+ private async getReviewAdaptation(): Promise<ReviewAdaptationState> {
137
+ const state = await this.getStrategyState<ReviewAdaptationState>();
138
+ return state || {
139
+ urgencyMultiplier: 1.0,
140
+ windowStart: new Date().toISOString(),
141
+ windowFailures: 0,
142
+ windowSuccesses: 0,
143
+ lastUpdated: new Date().toISOString(),
144
+ };
145
+ }
146
+
147
+ // Called after review outcome recorded (needs integration hook)
148
+ async updateReviewAdaptation(success: boolean): Promise<void> {
149
+ const state = await this.getReviewAdaptation();
150
+
151
+ if (success) {
152
+ state.urgencyMultiplier = Math.max(0.5, state.urgencyMultiplier - 0.01);
153
+ state.windowSuccesses++;
154
+ } else {
155
+ state.urgencyMultiplier = Math.min(2.0, state.urgencyMultiplier + 0.05);
156
+ state.windowFailures++;
157
+ }
158
+
159
+ state.lastUpdated = new Date().toISOString();
160
+ await this.putStrategyState(state);
161
+ }
162
+ ```
163
+
164
+ ### Required Work
165
+
166
+ - [ ] Add `getReviewAdaptation()` method to SRSNavigator
167
+ - [ ] Integrate `updateReviewAdaptation()` with card response recording flow
168
+ - [ ] Decide: Should multiplier affect backlog pressure or just base urgency?
169
+ - [ ] Consider reset behavior on long breaks (user returning after 6 months)
170
+ - [ ] Consider course-specific vs global multipliers
171
+ - [ ] Add provenance entry explaining multiplier contribution
172
+
173
+ ### Open Questions
174
+
175
+ 1. **Who calls `updateReviewAdaptation`?** — Needs hook into card response recording (currently in `UserDB.recordInteraction()` or similar)
176
+
177
+ 2. **Rolling window reset?** — Should the window reset periodically to allow recovery from bad streaks?
178
+
179
+ 3. **Visibility?** — Should users see their current multiplier? Could be motivating or discouraging.
180
+
181
+ 4. **Initial calibration?** — New users start at 1.0. Should there be an initial calibration period with more aggressive updates?
182
+
183
+ ### Priority
184
+
185
+ **Medium** — High value for learning outcomes, moderate implementation complexity. Requires integration with card response recording flow.
186
+
187
+ ---
188
+
189
+ ## Implementation Order
190
+
191
+ 1. ✅ **Backlog Pressure** (implemented) — Fixes immediate balance issue
192
+ 2. **Per-User Adaptation** — High value, moderate complexity
193
+ 3. **Orchestrator Tuning** — Lower priority if backlog pressure works well
194
+
195
+ ---
196
+
197
+ ## Related Files
198
+
199
+ | File | Purpose |
200
+ |------|---------|
201
+ | `core/navigators/generators/srs.ts` | SRS urgency calculation, backlog pressure |
202
+ | `core/orchestration/index.ts` | Orchestration context, deviation logic |
203
+ | `core/types/contentNavigationStrategy.ts` | Strategy config, learnable weights |
204
+ | `core/types/strategyState.ts` | Per-user strategy state storage |
205
+ | `impl/couch/userDB.ts` | User interaction recording |
@@ -53,7 +53,6 @@ interface HierarchyConfig {
53
53
  prerequisites: {
54
54
  [tagId: string]: TagPrerequisite[];
55
55
  };
56
- delegateStrategy?: string; // default: "elo"
57
56
  }
58
57
 
59
58
  interface TagPrerequisite {
@@ -75,8 +74,7 @@ interface TagPrerequisite {
75
74
  "blends": [
76
75
  { "tag": "cvc-words", "masteryThreshold": { "minCount": 20 } }
77
76
  ]
78
- },
79
- "delegateStrategy": "elo"
77
+ }
80
78
  }
81
79
  ```
82
80
 
@@ -99,7 +97,6 @@ interface InterferenceConfig {
99
97
  minElapsedDays?: number;
100
98
  };
101
99
  defaultDecay?: number;
102
- delegateStrategy?: string;
103
100
  }
104
101
 
105
102
  interface InterferenceGroup {
@@ -137,7 +134,6 @@ interface RelativePriorityConfig {
137
134
  defaultPriority?: number;
138
135
  combineMode?: 'max' | 'average' | 'min';
139
136
  priorityInfluence?: number;
140
- delegateStrategy?: string;
141
137
  }
142
138
  ```
143
139
 
@@ -398,4 +394,10 @@ The NavigationStrategy editor is accessible in:
398
394
  - `packages/db/src/core/navigators/hierarchyDefinition.ts` — Config interface reference
399
395
  - `packages/db/src/core/navigators/interferenceMitigator.ts` — Config interface reference
400
396
  - `packages/db/src/core/navigators/relativePriority.ts` — Config interface reference
401
- - `packages/edit-ui/src/components/NavigationStrategy/` — UI components (all forms)
397
+ - `packages/edit-ui/src/components/NavigationStrategy/` — UI components (all forms)
398
+
399
+ ## Related Documentation
400
+
401
+ - `navigators-architecture.md` — Pipeline architecture and strategy framework
402
+ - `future-orchestration-vision.md` — Long-term adaptive strategy vision
403
+ - `devlog/1032-orchestrator` — Evolutionary orchestration implementation details
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.1.23",
7
+ "version": "0.1.25",
8
8
  "description": "Database layer for vue-skuilder",
9
9
  "main": "dist/index.js",
10
10
  "module": "dist/index.mjs",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@nilock2/pouchdb-authentication": "^1.0.2",
51
- "@vue-skuilder/common": "0.1.23",
51
+ "@vue-skuilder/common": "0.1.25",
52
52
  "cross-fetch": "^4.1.0",
53
53
  "moment": "^2.29.4",
54
54
  "pouchdb": "^9.0.0",
@@ -62,5 +62,5 @@
62
62
  "vite": "^7.0.0",
63
63
  "vitest": "^4.0.15"
64
64
  },
65
- "stableVersion": "0.1.23"
65
+ "stableVersion": "0.1.25"
66
66
  }
package/src/core/index.ts CHANGED
@@ -4,7 +4,9 @@ export * from './interfaces';
4
4
  export * from './types/types-legacy';
5
5
  export * from './types/user';
6
6
  export * from './types/strategyState';
7
+ export * from './types/userOutcome';
7
8
  export * from '../util/Loggable';
8
9
  export * from './util';
9
10
  export * from './navigators';
10
11
  export * from './bulkImport';
12
+ export * from './orchestration';
@@ -4,6 +4,7 @@ import { StudentClassroomDB } from '../../impl/couch/classroomDB';
4
4
  import { WeightedCard } from '../navigators';
5
5
  import { TagFilter, hasActiveFilter } from '@vue-skuilder/common';
6
6
  import { TagFilteredContentSource } from '../../study/TagFilteredContentSource';
7
+ import { OrchestrationContext } from '../orchestration';
7
8
 
8
9
  export type StudySessionFailedItem = StudySessionFailedNewItem | StudySessionFailedReviewItem;
9
10
 
@@ -72,6 +73,12 @@ export interface StudyContentSource {
72
73
  * @returns Cards sorted by score descending
73
74
  */
74
75
  getWeightedCards(limit: number): Promise<WeightedCard[]>;
76
+
77
+ /**
78
+ * Get the orchestration context for this source.
79
+ * Used for recording learning outcomes.
80
+ */
81
+ getOrchestrationContext?(): Promise<OrchestrationContext>;
75
82
  }
76
83
  // #endregion docs_StudyContentSource
77
84