@vue-skuilder/db 0.1.18 → 0.1.21

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 (87) hide show
  1. package/CLAUDE.md +2 -2
  2. package/dist/{classroomDB-BgfrVb8d.d.ts → contentSource-BP9hznNV.d.ts} +220 -197
  3. package/dist/{classroomDB-CTOenngH.d.cts → contentSource-DsJadoBU.d.cts} +220 -197
  4. package/dist/core/index.d.cts +80 -6
  5. package/dist/core/index.d.ts +80 -6
  6. package/dist/core/index.js +735 -1560
  7. package/dist/core/index.js.map +1 -1
  8. package/dist/core/index.mjs +708 -1539
  9. package/dist/core/index.mjs.map +1 -1
  10. package/dist/{dataLayerProvider-D6PoCwS6.d.cts → dataLayerProvider-CHYrQ5pB.d.cts} +1 -1
  11. package/dist/{dataLayerProvider-CZxC9GtB.d.ts → dataLayerProvider-MDTxXq2l.d.ts} +1 -1
  12. package/dist/impl/couch/index.d.cts +8 -23
  13. package/dist/impl/couch/index.d.ts +8 -23
  14. package/dist/impl/couch/index.js +723 -1578
  15. package/dist/impl/couch/index.js.map +1 -1
  16. package/dist/impl/couch/index.mjs +692 -1552
  17. package/dist/impl/couch/index.mjs.map +1 -1
  18. package/dist/impl/static/index.d.cts +25 -8
  19. package/dist/impl/static/index.d.ts +25 -8
  20. package/dist/impl/static/index.js +700 -1400
  21. package/dist/impl/static/index.js.map +1 -1
  22. package/dist/impl/static/index.mjs +688 -1393
  23. package/dist/impl/static/index.mjs.map +1 -1
  24. package/dist/{index-D-Fa4Smt.d.cts → index-B_j6u5E4.d.cts} +1 -1
  25. package/dist/{index-CD8BZz2k.d.ts → index-Dj0SEgk3.d.ts} +1 -1
  26. package/dist/index.d.cts +71 -63
  27. package/dist/index.d.ts +71 -63
  28. package/dist/index.js +1162 -1996
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +1124 -1955
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/pouch/index.js +3 -0
  33. package/dist/pouch/index.js.map +1 -1
  34. package/dist/pouch/index.mjs +3 -0
  35. package/dist/pouch/index.mjs.map +1 -1
  36. package/dist/{types-CzPDLAK6.d.cts → types-Bn0itutr.d.cts} +1 -1
  37. package/dist/{types-CewsN87z.d.ts → types-DQaXnuoc.d.ts} +1 -1
  38. package/dist/{types-legacy-6ettoclI.d.cts → types-legacy-DDY4N-Uq.d.cts} +3 -1
  39. package/dist/{types-legacy-6ettoclI.d.ts → types-legacy-DDY4N-Uq.d.ts} +3 -1
  40. package/dist/util/packer/index.d.cts +3 -3
  41. package/dist/util/packer/index.d.ts +3 -3
  42. package/docs/navigators-architecture.md +115 -17
  43. package/package.json +4 -4
  44. package/src/core/index.ts +1 -0
  45. package/src/core/interfaces/classroomDB.ts +5 -13
  46. package/src/core/interfaces/contentSource.ts +6 -66
  47. package/src/core/interfaces/courseDB.ts +15 -7
  48. package/src/core/interfaces/userDB.ts +32 -0
  49. package/src/core/navigators/Pipeline.ts +136 -52
  50. package/src/core/navigators/PipelineAssembler.ts +1 -1
  51. package/src/core/navigators/defaults.ts +84 -0
  52. package/src/core/navigators/{hierarchyDefinition.ts → filters/hierarchyDefinition.ts} +15 -29
  53. package/src/core/navigators/filters/index.ts +3 -0
  54. package/src/core/navigators/filters/inferredPreferenceStub.ts +107 -0
  55. package/src/core/navigators/{interferenceMitigator.ts → filters/interferenceMitigator.ts} +11 -37
  56. package/src/core/navigators/{relativePriority.ts → filters/relativePriority.ts} +12 -38
  57. package/src/core/navigators/filters/userGoalStub.ts +136 -0
  58. package/src/core/navigators/filters/userTagPreference.ts +217 -0
  59. package/src/core/navigators/{CompositeGenerator.ts → generators/CompositeGenerator.ts} +15 -64
  60. package/src/core/navigators/{elo.ts → generators/elo.ts} +13 -63
  61. package/src/core/navigators/{srs.ts → generators/srs.ts} +11 -40
  62. package/src/core/navigators/generators/types.ts +1 -1
  63. package/src/core/navigators/index.ts +95 -91
  64. package/src/core/types/strategyState.ts +84 -0
  65. package/src/core/types/types-legacy.ts +2 -0
  66. package/src/impl/common/BaseUserDB.ts +74 -7
  67. package/src/impl/couch/adminDB.ts +1 -2
  68. package/src/impl/couch/classroomDB.ts +100 -103
  69. package/src/impl/couch/courseDB.ts +35 -91
  70. package/src/impl/couch/pouchdb-setup.ts +7 -0
  71. package/src/impl/static/StaticDataUnpacker.ts +50 -1
  72. package/src/impl/static/courseDB.ts +87 -37
  73. package/src/study/SessionController.ts +122 -202
  74. package/src/study/SourceMixer.ts +65 -0
  75. package/src/study/TagFilteredContentSource.ts +49 -92
  76. package/src/study/index.ts +1 -0
  77. package/src/study/services/CardHydrationService.ts +165 -81
  78. package/src/util/dataDirectory.ts +1 -1
  79. package/src/util/index.ts +0 -1
  80. package/tests/core/navigators/CompositeGenerator.test.ts +44 -168
  81. package/tests/core/navigators/Pipeline.test.ts +6 -72
  82. package/tests/core/navigators/PipelineAssembler.test.ts +8 -58
  83. package/tests/core/navigators/navigators.test.ts +118 -151
  84. package/docs/todo-pipeline-optimization.md +0 -117
  85. package/docs/todo-strategy-state-storage.md +0 -278
  86. package/src/core/navigators/hardcodedOrder.ts +0 -163
  87. package/src/util/tuiLogger.ts +0 -139
package/CLAUDE.md CHANGED
@@ -6,7 +6,7 @@ Database abstraction layer providing unified interfaces for CouchDB/PouchDB and
6
6
  - Build: `yarn workspace @vue-skuilder/db build`
7
7
  - Dev (watch): `yarn workspace @vue-skuilder/db dev`
8
8
  - Lint: `yarn workspace @vue-skuilder/db lint:fix`
9
- - Type check: `tsc --noEmit` (no dedicated script)
9
+ - Test: `yarn workspace @vue-skuilder/db test`
10
10
 
11
11
  ## Build System
12
12
  Uses **tsup** for dual CommonJS/ESM output:
@@ -40,4 +40,4 @@ Multiple entry points for different use cases:
40
40
  - **Provider Pattern**: Switchable backend implementations
41
41
  - **Dual Export**: Works in both Node.js and browser environments
42
42
  - **Type Safety**: Full TypeScript coverage with strict mode
43
- - **Sync Strategy**: Configurable online/offline data synchronization
43
+ - **Sync Strategy**: Configurable online/offline data synchronization
@@ -1,6 +1,6 @@
1
- import { CourseConfig, ClassroomConfig, CourseElo, Status, SkuilderCourseData as SkuilderCourseData$1, DataShape, TagFilter } from '@vue-skuilder/common';
1
+ import { CourseConfig, ClassroomConfig, Status, SkuilderCourseData as SkuilderCourseData$1, CourseElo, DataShape, TagFilter } from '@vue-skuilder/common';
2
2
  import { Moment } from 'moment';
3
- import { S as SkuilderCourseData, b as DocTypePrefixes, D as DocType, Q as QualifiedCardID, T as TagStub, a as Tag, C as CardHistory, c as CardRecord } from './types-legacy-6ettoclI.js';
3
+ import { S as SkuilderCourseData, b as DocTypePrefixes, D as DocType, Q as QualifiedCardID, T as TagStub, a as Tag, C as CardHistory, c as CardRecord } from './types-legacy-DDY4N-Uq.js';
4
4
 
5
5
  /**
6
6
  * Admin functionality
@@ -26,82 +26,63 @@ interface AdminDBInterface {
26
26
  })[]>;
27
27
  }
28
28
 
29
- interface SessionTrackingData {
30
- peekSessionCount: number;
31
- studySessionCount: number;
32
- sessionCount: number;
33
- firstSessionDate: string;
34
- lastSessionDate: string;
35
- signupPrompted: boolean;
36
- promptDismissalCount: number;
37
- studyModeAcknowledged: boolean;
38
- }
39
- interface UserConfig {
40
- darkMode: boolean;
41
- likesConfetti: boolean;
42
- sessionTimeLimit: number;
43
- email?: string;
44
- sessionTracking?: Record<string, SessionTrackingData>;
45
- }
46
- interface ActivityRecord {
47
- timeStamp: number | string;
48
- [key: string]: any;
49
- }
50
- interface CourseRegistration {
51
- status?: 'active' | 'dropped' | 'maintenance-mode' | 'preview';
52
- courseID: string;
53
- admin: boolean;
54
- moderator: boolean;
55
- user: boolean;
56
- settings?: {
57
- [setting: string]: string | number | boolean;
58
- };
59
- elo: number | CourseElo;
60
- }
61
- interface StudyWeights {
62
- [courseID: string]: number;
63
- }
64
- interface CourseRegistrationDoc {
65
- courses: CourseRegistration[];
66
- studyWeight: StudyWeights;
67
- }
68
- interface ScheduledCard {
69
- _id: PouchDB.Core.DocumentId;
29
+ /**
30
+ * Classroom management
31
+ */
32
+ interface ClassroomDBInterface {
70
33
  /**
71
- * The docID of the card to be reviewed
34
+ * Get classroom config
72
35
  */
73
- cardId: PouchDB.Core.DocumentId;
36
+ getConfig(): ClassroomConfig;
74
37
  /**
75
- * The ID of the course
38
+ * Get assigned content
76
39
  */
77
- courseId: string;
40
+ getAssignedContent(): Promise<AssignedContent[]>;
41
+ }
42
+ interface TeacherClassroomDBInterface extends ClassroomDBInterface {
78
43
  /**
79
- * The time at which the card becomes eligible for review.
80
- *
81
- * (Should probably be UTC adjusted so that performance is
82
- * not wonky across time zones)
83
- *
84
- * Note: Stored as ISO string for PouchDB serialization compatibility,
85
- * but can be consumed as Moment objects via moment.utc(reviewTime)
44
+ * For teacher interfaces: assign content
86
45
  */
87
- reviewTime: string | Moment;
46
+ assignContent?(content: AssignedContent): Promise<boolean>;
88
47
  /**
89
- * The time at which this scheduled event was created.
90
- *
91
- * Note: Stored as ISO string for PouchDB serialization compatibility,
92
- * but can be consumed as Moment objects via moment.utc(scheduledAt)
48
+ * For teacher interfaces: remove content
93
49
  */
94
- scheduledAt: string | Moment;
50
+ removeContent?(content: AssignedContent): Promise<void>;
51
+ }
52
+ /**
53
+ * Student-facing classroom interface.
54
+ * Content is accessed via StudyContentSource.getWeightedCards().
55
+ */
56
+ type StudentClassroomDBInterface = ClassroomDBInterface;
57
+ type AssignedContent = AssignedCourse | AssignedTag | AssignedCard;
58
+ interface AssignedTag extends ContentBase {
59
+ type: 'tag';
60
+ tagID: string;
61
+ }
62
+ interface AssignedCourse extends ContentBase {
63
+ type: 'course';
64
+ }
65
+ interface AssignedCard extends ContentBase {
66
+ type: 'card';
67
+ cardID: string;
68
+ }
69
+ interface ContentBase {
70
+ type: 'course' | 'tag' | 'card';
95
71
  /**
96
- * Classifying whether this card is scheduled on behalf of a
97
- * user-registered course or by as assigned content from a
98
- * user-registered classroom
72
+ * Username of the assigning teacher.
99
73
  */
100
- scheduledFor: 'course' | 'classroom';
74
+ assignedBy: string;
101
75
  /**
102
- * The ID of the course or classroom that requested this card
76
+ * Date the content was assigned.
103
77
  */
104
- schedulingAgentId: string;
78
+ assignedOn: moment.Moment;
79
+ /**
80
+ * A 'due' date for this assigned content, for scheduling content
81
+ * in advance. Content will not be actively pushed to students until
82
+ * this date.
83
+ */
84
+ activeOn: moment.Moment;
85
+ courseID: string;
105
86
  }
106
87
 
107
88
  interface DataLayerResult {
@@ -178,7 +159,7 @@ interface CourseInfo {
178
159
  cardCount: number;
179
160
  registeredUsers: number;
180
161
  }
181
- interface CourseDBInterface extends NavigationStrategyManager {
162
+ interface CourseDBInterface extends NavigationStrategyManager, StudyContentSource {
182
163
  /**
183
164
  * Get course config
184
165
  */
@@ -207,10 +188,6 @@ interface CourseDBInterface extends NavigationStrategyManager {
207
188
  * Update card ELO rating
208
189
  */
209
190
  updateCardElo(cardId: string, elo: CourseElo): Promise<PouchDB.Core.Response>;
210
- /**
211
- * Get new cards for study
212
- */
213
- getNewCards(limit?: number): Promise<StudySessionNewItem[]>;
214
191
  /**
215
192
  * Get cards centered at a particular ELO rating
216
193
  */
@@ -222,6 +199,18 @@ interface CourseDBInterface extends NavigationStrategyManager {
222
199
  * Get tags for a card
223
200
  */
224
201
  getAppliedTags(cardId: string): Promise<PouchDB.Query.Response<TagStub>>;
202
+ /**
203
+ * Get tags for multiple cards in a single batch query.
204
+ * More efficient than calling getAppliedTags() for each card.
205
+ *
206
+ * This method reduces redundant database operations when multiple filters
207
+ * need tag data for the same cards. The Pipeline uses this to pre-hydrate
208
+ * tags on WeightedCard objects before filters run.
209
+ *
210
+ * @param cardIds - Array of card IDs to fetch tags for
211
+ * @returns Map from cardId to array of tag names
212
+ */
213
+ getAppliedTagsBatch(cardIds: string[]): Promise<Map<string, string[]>>;
225
214
  /**
226
215
  * Add a tag to a card
227
216
  */
@@ -273,6 +262,84 @@ interface CourseDBInterface extends NavigationStrategyManager {
273
262
  find(request: PouchDB.Find.FindRequest<any>): Promise<PouchDB.Find.FindResponse<any>>;
274
263
  }
275
264
 
265
+ interface SessionTrackingData {
266
+ peekSessionCount: number;
267
+ studySessionCount: number;
268
+ sessionCount: number;
269
+ firstSessionDate: string;
270
+ lastSessionDate: string;
271
+ signupPrompted: boolean;
272
+ promptDismissalCount: number;
273
+ studyModeAcknowledged: boolean;
274
+ }
275
+ interface UserConfig {
276
+ darkMode: boolean;
277
+ likesConfetti: boolean;
278
+ sessionTimeLimit: number;
279
+ email?: string;
280
+ sessionTracking?: Record<string, SessionTrackingData>;
281
+ }
282
+ interface ActivityRecord {
283
+ timeStamp: number | string;
284
+ [key: string]: any;
285
+ }
286
+ interface CourseRegistration {
287
+ status?: 'active' | 'dropped' | 'maintenance-mode' | 'preview';
288
+ courseID: string;
289
+ admin: boolean;
290
+ moderator: boolean;
291
+ user: boolean;
292
+ settings?: {
293
+ [setting: string]: string | number | boolean;
294
+ };
295
+ elo: number | CourseElo;
296
+ }
297
+ interface StudyWeights {
298
+ [courseID: string]: number;
299
+ }
300
+ interface CourseRegistrationDoc {
301
+ courses: CourseRegistration[];
302
+ studyWeight: StudyWeights;
303
+ }
304
+ interface ScheduledCard {
305
+ _id: PouchDB.Core.DocumentId;
306
+ /**
307
+ * The docID of the card to be reviewed
308
+ */
309
+ cardId: PouchDB.Core.DocumentId;
310
+ /**
311
+ * The ID of the course
312
+ */
313
+ courseId: string;
314
+ /**
315
+ * The time at which the card becomes eligible for review.
316
+ *
317
+ * (Should probably be UTC adjusted so that performance is
318
+ * not wonky across time zones)
319
+ *
320
+ * Note: Stored as ISO string for PouchDB serialization compatibility,
321
+ * but can be consumed as Moment objects via moment.utc(reviewTime)
322
+ */
323
+ reviewTime: string | Moment;
324
+ /**
325
+ * The time at which this scheduled event was created.
326
+ *
327
+ * Note: Stored as ISO string for PouchDB serialization compatibility,
328
+ * but can be consumed as Moment objects via moment.utc(scheduledAt)
329
+ */
330
+ scheduledAt: string | Moment;
331
+ /**
332
+ * Classifying whether this card is scheduled on behalf of a
333
+ * user-registered course or by as assigned content from a
334
+ * user-registered classroom
335
+ */
336
+ scheduledFor: 'course' | 'classroom';
337
+ /**
338
+ * The ID of the course or classroom that requested this card
339
+ */
340
+ schedulingAgentId: string;
341
+ }
342
+
276
343
  type Update<T> = Partial<T> | ((x: T) => T);
277
344
 
278
345
  interface DocumentUpdater {
@@ -323,6 +390,17 @@ interface UserDBReader {
323
390
  */
324
391
  getPendingReviews(courseId?: string): Promise<ScheduledCard[]>;
325
392
  getActivityRecords(): Promise<ActivityRecord[]>;
393
+ /**
394
+ * Get strategy-specific state for a course.
395
+ *
396
+ * Strategies use this to persist preferences, learned patterns, or temporal
397
+ * tracking data across sessions. Each strategy owns its own namespace.
398
+ *
399
+ * @param courseId - The course this state applies to
400
+ * @param strategyKey - Unique key identifying the strategy (typically class name)
401
+ * @returns The strategy's data payload, or null if no state exists
402
+ */
403
+ getStrategyState<T>(courseId: string, strategyKey: string): Promise<T | null>;
326
404
  /**
327
405
  * Get user's classroom registrations
328
406
  */
@@ -387,6 +465,24 @@ interface UserDBWriter extends DocumentUpdater {
387
465
  status: Status;
388
466
  error?: string;
389
467
  }>;
468
+ /**
469
+ * Store strategy-specific state for a course.
470
+ *
471
+ * Strategies use this to persist preferences, learned patterns, or temporal
472
+ * tracking data across sessions. Each strategy owns its own namespace.
473
+ *
474
+ * @param courseId - The course this state applies to
475
+ * @param strategyKey - Unique key identifying the strategy (typically class name)
476
+ * @param data - The strategy's data payload to store
477
+ */
478
+ putStrategyState<T>(courseId: string, strategyKey: string, data: T): Promise<void>;
479
+ /**
480
+ * Delete strategy-specific state for a course.
481
+ *
482
+ * @param courseId - The course this state applies to
483
+ * @param strategyKey - Unique key identifying the strategy (typically class name)
484
+ */
485
+ deleteStrategyState(courseId: string, strategyKey: string): Promise<void>;
390
486
  }
391
487
  /**
392
488
  * Authentication and account management operations
@@ -524,6 +620,17 @@ interface WeightedCard {
524
620
  * First entry is from the generator, subsequent entries from filters.
525
621
  */
526
622
  provenance: StrategyContribution[];
623
+ /**
624
+ * Pre-fetched tags. Populated by Pipeline before filters run.
625
+ * Filters should use this instead of querying getAppliedTags() individually.
626
+ */
627
+ tags?: string[];
628
+ /**
629
+ * Review document ID (_id from ScheduledCard).
630
+ * Present when this card originated from SRS review scheduling.
631
+ * Used by SessionController to track review outcomes and maintain review state.
632
+ */
633
+ reviewID?: string;
527
634
  }
528
635
  /**
529
636
  * Extract card origin from provenance trail.
@@ -539,10 +646,10 @@ declare function getCardOrigin(card: WeightedCard): 'new' | 'review' | 'failed';
539
646
  declare enum Navigators {
540
647
  ELO = "elo",
541
648
  SRS = "srs",
542
- HARDCODED = "hardcodedOrder",
543
649
  HIERARCHY = "hierarchyDefinition",
544
650
  INTERFERENCE = "interferenceMitigator",
545
- RELATIVE_PRIORITY = "relativePriority"
651
+ RELATIVE_PRIORITY = "relativePriority",
652
+ USER_TAG_PREFERENCE = "userTagPreference"
546
653
  }
547
654
  /**
548
655
  * Role classification for navigation strategies.
@@ -584,9 +691,9 @@ declare function isFilter(impl: string): boolean;
584
691
  */
585
692
  declare abstract class ContentNavigator implements StudyContentSource {
586
693
  /** User interface for this navigation session */
587
- protected user?: UserDBInterface;
694
+ protected user: UserDBInterface;
588
695
  /** Course interface for this navigation session */
589
- protected course?: CourseDBInterface;
696
+ protected course: CourseDBInterface;
590
697
  /** Human-readable name for this strategy instance (from ContentNavigationStrategyData.name) */
591
698
  protected strategyName?: string;
592
699
  /** Unique document ID for this strategy instance (from ContentNavigationStrategyData._id) */
@@ -595,34 +702,41 @@ declare abstract class ContentNavigator implements StudyContentSource {
595
702
  * Constructor for standard navigators.
596
703
  * Call this from subclass constructors to initialize common fields.
597
704
  *
598
- * Note: CompositeGenerator doesn't use this pattern and should call super() without args.
705
+ * Note: CompositeGenerator and Pipeline call super() without args, then set
706
+ * user/course fields directly if needed.
599
707
  */
600
708
  constructor(user?: UserDBInterface, course?: CourseDBInterface, strategyData?: ContentNavigationStrategyData);
601
709
  /**
602
- * Factory method to create navigator instances dynamically.
710
+ * Unique key identifying this strategy for state storage.
603
711
  *
604
- * @param user - User interface
605
- * @param course - Course interface
606
- * @param strategyData - Strategy configuration document
607
- * @returns the runtime object used to steer a study session.
712
+ * Defaults to the constructor name (e.g., "UserTagPreferenceFilter").
713
+ * Override in subclasses if multiple instances of the same strategy type
714
+ * need separate state storage.
608
715
  */
609
- static create(user: UserDBInterface, course: CourseDBInterface, strategyData: ContentNavigationStrategyData): Promise<ContentNavigator>;
716
+ protected get strategyKey(): string;
610
717
  /**
611
- * Get cards scheduled for review.
718
+ * Get this strategy's persisted state for the current course.
612
719
  *
613
- * @deprecated This method is part of the legacy StudyContentSource interface.
614
- * New strategies should focus on implementing CardGenerator.getWeightedCards() instead.
720
+ * @returns The strategy's data payload, or null if no state exists
721
+ * @throws Error if user or course is not initialized
615
722
  */
616
- abstract getPendingReviews(): Promise<(StudySessionReviewItem & ScheduledCard)[]>;
723
+ protected getStrategyState<T>(): Promise<T | null>;
617
724
  /**
618
- * Get new cards for introduction.
725
+ * Persist this strategy's state for the current course.
619
726
  *
620
- * @deprecated This method is part of the legacy StudyContentSource interface.
621
- * New strategies should focus on implementing CardGenerator.getWeightedCards() instead.
727
+ * @param data - The strategy's data payload to store
728
+ * @throws Error if user or course is not initialized
729
+ */
730
+ protected putStrategyState<T>(data: T): Promise<void>;
731
+ /**
732
+ * Factory method to create navigator instances dynamically.
622
733
  *
623
- * @param n - Maximum number of new cards to return
734
+ * @param user - User interface
735
+ * @param course - Course interface
736
+ * @param strategyData - Strategy configuration document
737
+ * @returns the runtime object used to steer a study session.
624
738
  */
625
- abstract getNewCards(n?: number): Promise<StudySessionNewItem[]>;
739
+ static create(user: UserDBInterface, course: CourseDBInterface, strategyData: ContentNavigationStrategyData): Promise<ContentNavigator>;
626
740
  /**
627
741
  * Get cards with suitability scores and provenance trails.
628
742
  *
@@ -632,25 +746,23 @@ declare abstract class ContentNavigator implements StudyContentSource {
632
746
  * better candidates for presentation. Each card includes a provenance trail
633
747
  * documenting how strategies contributed to the final score.
634
748
  *
749
+ * ## Implementation Required
750
+ * All navigation strategies MUST override this method. The base class does
751
+ * not provide a default implementation.
752
+ *
635
753
  * ## For Generators
636
754
  * Override this method to generate candidates and compute scores based on
637
755
  * your strategy's logic (e.g., ELO proximity, review urgency). Create the
638
756
  * initial provenance entry with action='generated'.
639
757
  *
640
- * ## Default Implementation
641
- * The base class provides a backward-compatible default that:
642
- * 1. Calls legacy getNewCards() and getPendingReviews()
643
- * 2. Assigns score=1.0 to all cards
644
- * 3. Creates minimal provenance from legacy methods
645
- * 4. Returns combined results up to limit
646
- *
647
- * This allows existing strategies to work without modification while
648
- * new strategies can override with proper scoring and provenance.
758
+ * ## For Filters
759
+ * Filters should implement the CardFilter interface instead and be composed
760
+ * via Pipeline. Filters do not directly implement getWeightedCards().
649
761
  *
650
762
  * @param limit - Maximum cards to return
651
763
  * @returns Cards sorted by score descending, with provenance trails
652
764
  */
653
- getWeightedCards(limit: number): Promise<WeightedCard[]>;
765
+ getWeightedCards(_limit: number): Promise<WeightedCard[]>;
654
766
  }
655
767
 
656
768
  type StudySessionFailedItem = StudySessionFailedNewItem | StudySessionFailedReviewItem;
@@ -688,112 +800,23 @@ interface ContentSourceID {
688
800
  /**
689
801
  * Interface for sources that provide study content to SessionController.
690
802
  *
691
- * @deprecated This interface will be superseded by ContentNavigator.getWeightedCards().
692
- * The getNewCards/getPendingReviews split was an artifact of hard-coded ELO and SRS
693
- * strategies. The new API returns unified WeightedCard[] with scores.
803
+ * Content sources return scored candidates via getWeightedCards(), which
804
+ * SessionController uses to populate study queues.
694
805
  *
695
- * MIGRATION:
696
- * - Implement ContentNavigator instead of StudyContentSource directly
697
- * - Override getWeightedCards() as the primary method
698
- * - Legacy methods can delegate to getWeightedCards() or be left as-is
699
- *
700
- * See: packages/db/src/core/navigators/ARCHITECTURE.md
806
+ * See: packages/db/docs/navigators-architecture.md
701
807
  */
702
808
  interface StudyContentSource {
703
- /**
704
- * Get cards scheduled for review based on SRS algorithm.
705
- *
706
- * @deprecated Will be replaced by getWeightedCards() which returns scored candidates.
707
- * Review urgency will be expressed as a score rather than a separate method.
708
- */
709
- getPendingReviews(): Promise<(StudySessionReviewItem & ScheduledCard)[]>;
710
- /**
711
- * Get new cards for introduction, typically ordered by ELO proximity.
712
- *
713
- * @deprecated Will be replaced by getWeightedCards() which returns scored candidates.
714
- * New card selection and scoring will be unified with review scoring.
715
- *
716
- * @param n - Maximum number of new cards to return
717
- */
718
- getNewCards(n?: number): Promise<StudySessionNewItem[]>;
719
809
  /**
720
810
  * Get cards with suitability scores for presentation.
721
811
  *
722
- * This is the PRIMARY API for content sources going forward. Returns unified
723
- * scored candidates that can be sorted and selected by SessionController.
724
- *
725
- * The `source` field on WeightedCard indicates origin ('new' | 'review' | 'failed')
726
- * for queue routing purposes during the migration period.
812
+ * Returns unified scored candidates that can be sorted and selected by SessionController.
813
+ * The card origin ('new' | 'review' | 'failed') is determined by provenance metadata.
727
814
  *
728
815
  * @param limit - Maximum number of cards to return
729
816
  * @returns Cards sorted by score descending
730
817
  */
731
- getWeightedCards?(limit: number): Promise<WeightedCard[]>;
818
+ getWeightedCards(limit: number): Promise<WeightedCard[]>;
732
819
  }
733
820
  declare function getStudySource(source: ContentSourceID, user: UserDBInterface): Promise<StudyContentSource>;
734
821
 
735
- /**
736
- * Classroom management
737
- */
738
- interface ClassroomDBInterface {
739
- /**
740
- * Get classroom config
741
- */
742
- getConfig(): ClassroomConfig;
743
- /**
744
- * Get assigned content
745
- */
746
- getAssignedContent(): Promise<AssignedContent[]>;
747
- }
748
- interface TeacherClassroomDBInterface extends ClassroomDBInterface {
749
- /**
750
- * For teacher interfaces: assign content
751
- */
752
- assignContent?(content: AssignedContent): Promise<boolean>;
753
- /**
754
- * For teacher interfaces: remove content
755
- */
756
- removeContent?(content: AssignedContent): Promise<void>;
757
- }
758
- interface StudentClassroomDBInterface extends ClassroomDBInterface {
759
- /**
760
- * For student interfaces: get pending reviews
761
- */
762
- getPendingReviews?(): Promise<(StudySessionReviewItem & ScheduledCard)[]>;
763
- /**
764
- * For student interfaces: get new cards
765
- */
766
- getNewCards?(limit?: number): Promise<StudySessionNewItem[]>;
767
- }
768
- type AssignedContent = AssignedCourse | AssignedTag | AssignedCard;
769
- interface AssignedTag extends ContentBase {
770
- type: 'tag';
771
- tagID: string;
772
- }
773
- interface AssignedCourse extends ContentBase {
774
- type: 'course';
775
- }
776
- interface AssignedCard extends ContentBase {
777
- type: 'card';
778
- cardID: string;
779
- }
780
- interface ContentBase {
781
- type: 'course' | 'tag' | 'card';
782
- /**
783
- * Username of the assigning teacher.
784
- */
785
- assignedBy: string;
786
- /**
787
- * Date the content was assigned.
788
- */
789
- assignedOn: moment.Moment;
790
- /**
791
- * A 'due' date for this assigned content, for scheduling content
792
- * in advance. Content will not be actively pushed to students until
793
- * this date.
794
- */
795
- activeOn: moment.Moment;
796
- courseID: string;
797
- }
798
-
799
- export { type AdminDBInterface as A, type UsrCrsDataInterface as B, type CourseDBInterface as C, type DataLayerResult as D, type ClassroomRegistrationDesignation as E, type ClassroomRegistration as F, type ClassroomRegistrationDoc as G, type SessionTrackingData as H, type UserConfig as I, type ActivityRecord as J, type CourseRegistration as K, type StrategyContribution as L, getCardOrigin as M, Navigators as N, NavigatorRole as O, NavigatorRoles as P, isGenerator as Q, isFilter as R, type StudySessionNewItem as S, type TeacherClassroomDBInterface as T, type UserDBInterface as U, type DocumentUpdater as V, type WeightedCard as W, newInterval as X, type UserDBReader as a, type CoursesDBInterface as b, type ClassroomDBInterface as c, type CourseInfo as d, type ContentNavigationStrategyData as e, type StudySessionReviewItem as f, type ScheduledCard as g, type AssignedContent as h, type StudyContentSource as i, type StudentClassroomDBInterface as j, ContentNavigator as k, type StudySessionItem as l, type StudySessionFailedItem as m, type StudySessionFailedNewItem as n, type StudySessionFailedReviewItem as o, isReview as p, type ContentSourceID as q, getStudySource as r, type CourseRegistrationDoc as s, type AssignedTag as t, type AssignedCourse as u, type AssignedCard as v, type UserDBWriter as w, type UserDBAuthenticator as x, type UserCourseSettings as y, type UserCourseSetting as z };
822
+ export { type AdminDBInterface as A, type UsrCrsDataInterface as B, type CourseDBInterface as C, type DataLayerResult as D, type ClassroomRegistrationDesignation as E, type ClassroomRegistration as F, type ClassroomRegistrationDoc as G, type SessionTrackingData as H, type UserConfig as I, type ActivityRecord as J, type CourseRegistration as K, type StrategyContribution as L, getCardOrigin as M, Navigators as N, NavigatorRole as O, NavigatorRoles as P, isGenerator as Q, isFilter as R, type StudySessionItem as S, type TeacherClassroomDBInterface as T, type UserDBInterface as U, type DocumentUpdater as V, type WeightedCard as W, newInterval as X, type UserDBReader as a, type CoursesDBInterface as b, type ClassroomDBInterface as c, type CourseInfo as d, type ContentNavigationStrategyData as e, ContentNavigator as f, type AssignedContent as g, type StudyContentSource as h, type StudentClassroomDBInterface as i, type ScheduledCard as j, type StudySessionFailedItem as k, type StudySessionFailedNewItem as l, type StudySessionFailedReviewItem as m, type StudySessionNewItem as n, type StudySessionReviewItem as o, isReview as p, type ContentSourceID as q, getStudySource as r, type CourseRegistrationDoc as s, type AssignedTag as t, type AssignedCourse as u, type AssignedCard as v, type UserDBWriter as w, type UserDBAuthenticator as x, type UserCourseSettings as y, type UserCourseSetting as z };