@vue-skuilder/db 0.1.32-c → 0.1.32-e

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 (55) hide show
  1. package/dist/{dataLayerProvider-BAn-LRh5.d.ts → contentSource-BMlMwSiG.d.cts} +202 -626
  2. package/dist/{dataLayerProvider-BJqBlMIl.d.cts → contentSource-Ht3N2f-y.d.ts} +202 -626
  3. package/dist/core/index.d.cts +23 -84
  4. package/dist/core/index.d.ts +23 -84
  5. package/dist/core/index.js +476 -1819
  6. package/dist/core/index.js.map +1 -1
  7. package/dist/core/index.mjs +456 -1803
  8. package/dist/core/index.mjs.map +1 -1
  9. package/dist/dataLayerProvider-BEqB8VBR.d.cts +67 -0
  10. package/dist/dataLayerProvider-DObSXjnf.d.ts +67 -0
  11. package/dist/impl/couch/index.d.cts +5 -5
  12. package/dist/impl/couch/index.d.ts +5 -5
  13. package/dist/impl/couch/index.js +484 -1827
  14. package/dist/impl/couch/index.js.map +1 -1
  15. package/dist/impl/couch/index.mjs +460 -1807
  16. package/dist/impl/couch/index.mjs.map +1 -1
  17. package/dist/impl/static/index.d.cts +5 -4
  18. package/dist/impl/static/index.d.ts +5 -4
  19. package/dist/impl/static/index.js +458 -1801
  20. package/dist/impl/static/index.js.map +1 -1
  21. package/dist/impl/static/index.mjs +437 -1784
  22. package/dist/impl/static/index.mjs.map +1 -1
  23. package/dist/{index-X6wHrURm.d.ts → index-BWvO-_rJ.d.ts} +1 -1
  24. package/dist/{index-m8MMGxxR.d.cts → index-Ba7hYbHj.d.cts} +1 -1
  25. package/dist/index.d.cts +461 -11
  26. package/dist/index.d.ts +461 -11
  27. package/dist/index.js +9239 -9159
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +9129 -9049
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/{types-DZ5dUqbL.d.ts → types-CJrLM1Ew.d.ts} +1 -1
  32. package/dist/{types-ZL8tOPQZ.d.cts → types-W8n-B6HG.d.cts} +1 -1
  33. package/dist/{types-legacy-C7r0T4OV.d.cts → types-legacy-JXDxinpU.d.cts} +1 -1
  34. package/dist/{types-legacy-C7r0T4OV.d.ts → types-legacy-JXDxinpU.d.ts} +1 -1
  35. package/dist/util/packer/index.d.cts +3 -3
  36. package/dist/util/packer/index.d.ts +3 -3
  37. package/package.json +2 -2
  38. package/src/core/interfaces/contentSource.ts +2 -3
  39. package/src/core/navigators/Pipeline.ts +60 -6
  40. package/src/core/navigators/PipelineDebugger.ts +103 -0
  41. package/src/core/navigators/filters/hierarchyDefinition.ts +2 -1
  42. package/src/core/navigators/filters/interferenceMitigator.ts +2 -1
  43. package/src/core/navigators/filters/relativePriority.ts +2 -1
  44. package/src/core/navigators/filters/userTagPreference.ts +2 -1
  45. package/src/core/navigators/generators/CompositeGenerator.ts +58 -5
  46. package/src/core/navigators/generators/elo.ts +7 -7
  47. package/src/core/navigators/generators/prescribed.ts +124 -35
  48. package/src/core/navigators/generators/srs.ts +3 -4
  49. package/src/core/navigators/generators/types.ts +48 -2
  50. package/src/core/navigators/index.ts +3 -3
  51. package/src/impl/couch/classroomDB.ts +4 -3
  52. package/src/impl/couch/courseDB.ts +3 -3
  53. package/src/impl/static/courseDB.ts +3 -3
  54. package/src/study/SessionController.ts +5 -27
  55. package/src/study/TagFilteredContentSource.ts +4 -3
package/dist/index.d.ts CHANGED
@@ -1,14 +1,113 @@
1
- import { i as StudyContentSource, U as UserDBInterface, W as WeightedCard, t as SourceBatch, C as CourseDBInterface, D as DataLayerProvider } from './dataLayerProvider-BAn-LRh5.js';
2
- export { K as ActivityRecord, A as AdminDBInterface, w as AssignedCard, h as AssignedContent, v as AssignedCourse, u as AssignedTag, b as ClassroomDBInterface, G as ClassroomRegistration, F as ClassroomRegistrationDesignation, H as ClassroomRegistrationDoc, f as ContentNavigationStrategyData, g as ContentNavigator, r as ContentSourceID, d as CourseInfo, L as CourseRegistration, M as CourseRegistrationDoc, a as CoursesDBInterface, aj as DocumentUpdater, a6 as LearnableWeight, O as Loggable, P as NavigatorConstructor, a2 as NavigatorRole, a3 as NavigatorRoles, a1 as Navigators, a7 as OrchestrationContext, ai as QuotaRoundRobinMixer, R as ReplanHints, ac as ReplanOptions, af as ResponseResult, k as ScheduledCard, ae as SessionAction, ag as SessionController, I as SessionTrackingData, ah as SourceMixer, $ as StrategyContribution, j as StudentClassroomDBInterface, l as StudySessionFailedItem, m as StudySessionFailedNewItem, n as StudySessionFailedReviewItem, S as StudySessionItem, o as StudySessionNewItem, ad as StudySessionRecord, p as StudySessionReviewItem, T as TeacherClassroomDBInterface, J as UserConfig, B as UserCourseSetting, z as UserCourseSettings, y as UserDBAuthenticator, c as UserDBReader, x as UserDBWriter, N as UserOutcomeRecord, E as UsrCrsDataInterface, a8 as computeDeviation, aa as computeEffectiveWeight, a9 as computeSpread, ab as createOrchestrationContext, a0 as getCardOrigin, V as getRegisteredNavigator, Z as getRegisteredNavigatorNames, Y as getRegisteredNavigatorRole, s as getStudySource, X as hasRegisteredNavigator, _ as initializeNavigatorRegistry, a5 as isFilter, a4 as isGenerator, q as isReview, ak as newInterval, Q as registerNavigator } from './dataLayerProvider-BAn-LRh5.js';
3
- export { C as CardData, g as CardHistory, h as CardRecord, b as CourseListData, d as DataShapeData, c as DisplayableData, D as DocType, f as DocTypePrefixes, F as Field, G as GuestUsername, Q as QualifiedCardID, e as QuestionData, i as QuestionRecord, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from './types-legacy-C7r0T4OV.js';
4
- export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, CardGenerator, CardGeneratorFactory, FilterContext, FilterImpact, GeneratorContext, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig } from './core/index.js';
5
- import { TagFilter, DataShape, CourseConfig } from '@vue-skuilder/common';
6
- import { S as StaticCourseManifest } from './types-DZ5dUqbL.js';
7
- export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-DZ5dUqbL.js';
8
- import { F as FileSystemAdapter } from './index-X6wHrURm.js';
9
- export { C as CouchDBToStaticPacker, a as FileStats, b as FileSystemError } from './index-X6wHrURm.js';
1
+ import { U as UserDBInterface, s as CourseRegistrationDoc, S as StudySessionItem, W as WeightedCard, R as ReplanHints, h as StudyContentSource, G as GeneratorResult, C as CourseDBInterface } from './contentSource-Ht3N2f-y.js';
2
+ export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as AssignedContent, u as AssignedCourse, t as AssignedTag, a4 as CardGenerator, a6 as CardGeneratorFactory, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, H as ClassroomRegistrationDoc, e as ContentNavigationStrategyData, f as ContentNavigator, q as ContentSourceID, d as CourseInfo, L as CourseRegistration, b as CoursesDBInterface, ad as DocumentUpdater, a5 as GeneratorContext, a7 as LearnableWeight, N as NavigatorConstructor, a0 as NavigatorRole, a1 as NavigatorRoles, $ as Navigators, a8 as OrchestrationContext, j as ScheduledCard, I as SessionTrackingData, Z as StrategyContribution, i as StudentClassroomDBInterface, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, n as StudySessionNewItem, o as StudySessionReviewItem, T as TeacherClassroomDBInterface, J as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, M as UserOutcomeRecord, B as UsrCrsDataInterface, a9 as computeDeviation, ab as computeEffectiveWeight, aa as computeSpread, ac as createOrchestrationContext, _ as getCardOrigin, P as getRegisteredNavigator, X as getRegisteredNavigatorNames, V as getRegisteredNavigatorRole, r as getStudySource, Q as hasRegisteredNavigator, Y as initializeNavigatorRegistry, a3 as isFilter, a2 as isGenerator, p as isReview, ae as newInterval, O as registerNavigator } from './contentSource-Ht3N2f-y.js';
3
+ import { D as DataLayerProvider } from './dataLayerProvider-DObSXjnf.js';
4
+ import { C as CardHistory, c as CardRecord } from './types-legacy-JXDxinpU.js';
5
+ export { d as CardData, e as CourseListData, g as DataShapeData, f as DisplayableData, D as DocType, b as DocTypePrefixes, F as Field, G as GuestUsername, Q as QualifiedCardID, h as QuestionData, i as QuestionRecord, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from './types-legacy-JXDxinpU.js';
6
+ import { Loggable } from './core/index.js';
7
+ export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, FilterContext, FilterImpact, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig } from './core/index.js';
8
+ import { TaggedPerformance, TagFilter, DataShape, CourseConfig } from '@vue-skuilder/common';
9
+ import { S as StaticCourseManifest } from './types-CJrLM1Ew.js';
10
+ export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-CJrLM1Ew.js';
11
+ import { F as FileSystemAdapter } from './index-BWvO-_rJ.js';
12
+ export { C as CouchDBToStaticPacker, a as FileStats, b as FileSystemError } from './index-BWvO-_rJ.js';
10
13
  import 'moment';
11
14
 
15
+ /**
16
+ * Service responsible for ELO rating calculations and updates.
17
+ */
18
+ declare class EloService {
19
+ private dataLayer;
20
+ private user;
21
+ constructor(dataLayer: DataLayerProvider, user: UserDBInterface);
22
+ /**
23
+ * Updates both user and card ELO ratings based on user performance.
24
+ * @param userScore Score between 0-1 representing user performance
25
+ * @param course_id Course identifier
26
+ * @param card_id Card identifier
27
+ * @param userCourseRegDoc User's course registration document (will be mutated)
28
+ * @param currentCard Current card session record
29
+ * @param k Optional K-factor for ELO calculation
30
+ */
31
+ updateUserAndCardElo(userScore: number, course_id: string, card_id: string, userCourseRegDoc: CourseRegistrationDoc, currentCard: StudySessionRecord, k?: number): Promise<void>;
32
+ /**
33
+ * Updates both user and card ELO ratings with per-tag granularity.
34
+ * Tags in taggedPerformance but not on card will be created dynamically.
35
+ *
36
+ * @param taggedPerformance Performance object with _global and per-tag scores
37
+ * @param course_id Course identifier
38
+ * @param card_id Card identifier
39
+ * @param userCourseRegDoc User's course registration document (will be mutated)
40
+ * @param currentCard Current card session record
41
+ */
42
+ updateUserAndCardEloPerTag(taggedPerformance: TaggedPerformance, course_id: string, card_id: string, userCourseRegDoc: CourseRegistrationDoc, currentCard: StudySessionRecord): Promise<void>;
43
+ }
44
+
45
+ /**
46
+ * Service responsible for Spaced Repetition System (SRS) scheduling logic.
47
+ */
48
+ declare class SrsService {
49
+ private user;
50
+ constructor(user: UserDBInterface);
51
+ /**
52
+ * Remove a scheduled review from the user's database.
53
+ * Used to clean up orphaned reviews (e.g., card deleted from course DB).
54
+ */
55
+ removeReview(reviewID: string): void;
56
+ /**
57
+ * Calculates the next review time for a card based on its history and
58
+ * schedules it in the user's database.
59
+ * @param history The full history of the card.
60
+ * @param item The study session item, used to determine if a previous review needs to be cleared.
61
+ */
62
+ scheduleReview(history: CardHistory<CardRecord>, item: StudySessionItem): Promise<void>;
63
+ }
64
+
65
+ /**
66
+ * Service responsible for orchestrating the complete response processing workflow.
67
+ * Coordinates SRS scheduling and ELO updates for user card interactions.
68
+ */
69
+ declare class ResponseProcessor {
70
+ private srsService;
71
+ private eloService;
72
+ constructor(srsService: SrsService, eloService: EloService);
73
+ /**
74
+ * Parses performance data into global score and optional per-tag scores.
75
+ *
76
+ * @param performance - Numeric or structured performance from QuestionRecord
77
+ * @returns Parsed performance with global score and optional tag scores
78
+ */
79
+ private parsePerformance;
80
+ /**
81
+ * Processes a user's response to a card, handling SRS scheduling and ELO updates.
82
+ * @param cardRecord User's response record
83
+ * @param cardHistory Promise resolving to the card's history
84
+ * @param studySessionItem Current study session item
85
+ * @param courseRegistrationDoc User's course registration (for ELO updates)
86
+ * @param currentCard Current study session record
87
+ * @param courseId Course identifier
88
+ * @param cardId Card identifier
89
+ * @param maxAttemptsPerView Maximum attempts allowed per view
90
+ * @param maxSessionViews Maximum session views for this card
91
+ * @param sessionViews Current number of session views
92
+ * @returns ResponseResult with navigation and UI instructions
93
+ */
94
+ processResponse(cardRecord: CardRecord, cardHistory: Promise<CardHistory<CardRecord>>, studySessionItem: StudySessionItem, courseRegistrationDoc: CourseRegistrationDoc, currentCard: StudySessionRecord, courseId: string, cardId: string, maxAttemptsPerView: number, maxSessionViews: number, sessionViews: number): Promise<ResponseResult>;
95
+ /**
96
+ * Handles processing for correct responses: SRS scheduling and ELO updates.
97
+ */
98
+ private processCorrectResponse;
99
+ /**
100
+ * Handles processing for incorrect responses: ELO updates only.
101
+ */
102
+ private processIncorrectResponse;
103
+ }
104
+
105
+ interface HydratedCard<TView = unknown> {
106
+ item: StudySessionItem;
107
+ view: TView;
108
+ data: any[];
109
+ }
110
+
12
111
  interface MigrationOptions {
13
112
  chunkBatchSize: number;
14
113
  validateRoundTrip: boolean;
@@ -165,6 +264,357 @@ declare function getDbPath(dbName: string): string;
165
264
  */
166
265
  declare function initializeDataDirectory(): Promise<void>;
167
266
 
267
+ /**
268
+ * Represents a batch of content fetched from a single StudyContentSource.
269
+ */
270
+ interface SourceBatch {
271
+ sourceIndex: number;
272
+ weighted: WeightedCard[];
273
+ }
274
+ /**
275
+ * Strategy interface for mixing content from multiple sources into a unified
276
+ * set of weighted candidates.
277
+ *
278
+ * Different implementations can provide different balancing strategies:
279
+ * - QuotaRoundRobinMixer: Equal representation per source
280
+ * - MinMaxNormalizingMixer: Score normalization then global sort
281
+ * - PercentileBucketMixer: Bucketed round-robin
282
+ * etc.
283
+ */
284
+ interface SourceMixer {
285
+ /**
286
+ * Mix weighted cards from multiple sources into a unified, ordered list.
287
+ *
288
+ * @param batches - Content batches from each source
289
+ * @param limit - Target number of cards to return
290
+ * @returns Mixed and ordered weighted cards
291
+ */
292
+ mix(batches: SourceBatch[], limit: number): WeightedCard[];
293
+ }
294
+ /**
295
+ * Quota-based mixer with interleaved output.
296
+ *
297
+ * Allocates equal representation to each source (top-N by score), then
298
+ * interleaves the results by dealing from a randomly-shuffled source order.
299
+ * Within each source, cards are dealt in score-descending order.
300
+ *
301
+ * This ensures that cards from different courses are spread throughout the
302
+ * queue rather than clustered by score bands, which matters because
303
+ * SessionController consumes queues front-to-back and sessions often end
304
+ * before reaching the tail.
305
+ */
306
+ declare class QuotaRoundRobinMixer implements SourceMixer {
307
+ mix(batches: SourceBatch[], limit: number): WeightedCard[];
308
+ }
309
+
310
+ /**
311
+ * Options for requesting a mid-session replan.
312
+ *
313
+ * All fields are optional — callers can pass just the fields they need.
314
+ * When omitted, defaults match the existing behaviour (full 20-card
315
+ * replace with no hints).
316
+ */
317
+ interface ReplanOptions {
318
+ /** Scoring hints forwarded to the pipeline (boost/exclude/require). */
319
+ hints?: ReplanHints;
320
+ /**
321
+ * Maximum number of new cards to return from the pipeline.
322
+ * Default: 20 (the standard session batch size).
323
+ */
324
+ limit?: number;
325
+ /**
326
+ * How to integrate the new cards into the existing newQ.
327
+ * - `'replace'` (default): atomically swap the entire newQ.
328
+ * - `'merge'`: insert new cards at the front, keeping existing cards.
329
+ */
330
+ mode?: 'replace' | 'merge';
331
+ /**
332
+ * Guarantee that at least this many cards will be served after the
333
+ * replan, even if the session timer has expired. Prevents intro cards
334
+ * from surfacing at the end of a session with zero follow-up exercise.
335
+ * Decremented on each card draw while active.
336
+ */
337
+ minFollowUpCards?: number;
338
+ /**
339
+ * Human-readable label for debugging / provenance.
340
+ * Appears in console logs and in card provenance entries created
341
+ * by ephemeral hint application.
342
+ */
343
+ label?: string;
344
+ }
345
+ interface StudySessionRecord {
346
+ card: {
347
+ course_id: string;
348
+ card_id: string;
349
+ card_elo: number;
350
+ };
351
+ item: StudySessionItem;
352
+ records: CardRecord[];
353
+ }
354
+
355
+ type SessionAction = 'dismiss-success' | 'dismiss-failed' | 'marked-failed' | 'dismiss-error';
356
+ interface ResponseResult {
357
+ nextCardAction: Exclude<SessionAction, 'dismiss-error'> | 'none';
358
+ shouldLoadNextCard: boolean;
359
+ /**
360
+ * When true, the card requested deferred advancement via `deferAdvance`.
361
+ * The record was logged and ELO updated, but navigation was suppressed.
362
+ * StudySession should stash `nextCardAction` and wait for a
363
+ * `ready-to-advance` event from the card before calling `nextCard()`.
364
+ */
365
+ deferred?: boolean;
366
+ isCorrect: boolean;
367
+ performanceScore?: number;
368
+ shouldClearFeedbackShadow: boolean;
369
+ }
370
+ interface SessionServices {
371
+ response: ResponseProcessor;
372
+ }
373
+ declare class SessionController<TView = unknown> extends Loggable {
374
+ _className: string;
375
+ services: SessionServices;
376
+ private srsService;
377
+ private eloService;
378
+ private hydrationService;
379
+ private mixer;
380
+ private dataLayer;
381
+ private courseNameCache;
382
+ /**
383
+ * Default pipeline batch size for new-card planning.
384
+ * Set via constructor options; falls back to 20 when not specified.
385
+ * Individual replans can override via `ReplanOptions.limit`.
386
+ */
387
+ private _defaultBatchLimit;
388
+ private sources;
389
+ private _sessionRecord;
390
+ set sessionRecord(r: StudySessionRecord[]);
391
+ private _currentCard;
392
+ private reviewQ;
393
+ private newQ;
394
+ private failedQ;
395
+ /**
396
+ * Promise tracking a currently in-progress replan, or null if idle.
397
+ * Used by nextCard() to await completion before drawing from queues.
398
+ */
399
+ private _replanPromise;
400
+ /**
401
+ * Number of well-indicated new cards remaining before the queue
402
+ * degrades to poorly-indicated content. Decremented on each newQ
403
+ * draw; when it hits 0, a replan is triggered automatically
404
+ * (user state has changed from completing good cards).
405
+ */
406
+ private _wellIndicatedRemaining;
407
+ /**
408
+ * When true, suppresses the quality-based auto-replan trigger in
409
+ * nextCard(). Set after a burst replan (small limit) to prevent the
410
+ * auto-replan from clobbering the burst cards before they're consumed.
411
+ * Cleared when the depletion-triggered replan fires (newQ exhausted).
412
+ */
413
+ private _suppressQualityReplan;
414
+ /**
415
+ * Guards against infinite depletion-triggered replans. Set to true
416
+ * when a depletion replan fires; cleared when a replan produces
417
+ * content (newQ.length > 0 after replan) or when an explicit
418
+ * (non-auto) replan is requested.
419
+ */
420
+ private _depletionReplanAttempted;
421
+ /**
422
+ * When > 0, the session timer cannot end the session. Decremented on
423
+ * each nextCard() draw. Set by replans that include `minFollowUpCards`.
424
+ */
425
+ private _minCardsGuarantee;
426
+ private startTime;
427
+ private endTime;
428
+ private _secondsRemaining;
429
+ get secondsRemaining(): number;
430
+ /** True when a card guarantee is active, preventing timer-based session end. */
431
+ get hasCardGuarantee(): boolean;
432
+ get report(): string;
433
+ get detailedReport(): string;
434
+ private _intervalHandle;
435
+ /**
436
+ * @param sources - Array of content sources to mix for the session
437
+ * @param time - Session duration in seconds
438
+ * @param dataLayer - Data layer provider
439
+ * @param getViewComponent - Function to resolve view components
440
+ * @param mixer - Optional source mixer strategy (defaults to QuotaRoundRobinMixer)
441
+ * @param options - Optional session-level configuration
442
+ * @param options.defaultBatchLimit - Default pipeline batch size (default: 20).
443
+ * Smaller values for newer users cause more frequent replans, keeping plans
444
+ * aligned with rapidly-changing user state.
445
+ */
446
+ constructor(sources: StudyContentSource[], time: number, dataLayer: DataLayerProvider, getViewComponent: (viewId: string) => TView, mixer?: SourceMixer, options?: {
447
+ defaultBatchLimit?: number;
448
+ });
449
+ private tick;
450
+ /**
451
+ * Returns a rough, erring toward conservative, guess at
452
+ * the amount of time the failed cards queue will require
453
+ * to clean up.
454
+ *
455
+ * (seconds)
456
+ */
457
+ private estimateCleanupTime;
458
+ /**
459
+ * Extremely rough, conservative, estimate of amound of time to complete
460
+ * all scheduled reviews
461
+ */
462
+ private estimateReviewTime;
463
+ prepareSession(): Promise<void>;
464
+ /**
465
+ * Request a mid-session replan. Re-runs the pipeline with current user state
466
+ * and atomically replaces the newQ contents. Safe to call at any time during
467
+ * a session — if called while a replan is already in progress, returns the
468
+ * existing replan promise (no duplicate work).
469
+ *
470
+ * Does NOT affect reviewQ or failedQ.
471
+ *
472
+ * If nextCard() is called while a replan is in flight, it will automatically
473
+ * await the replan before drawing from queues, ensuring the user always sees
474
+ * cards scored against their latest state.
475
+ *
476
+ * Typical trigger: application-level code (e.g. after a GPC intro completion)
477
+ * calls this to ensure newly-unlocked content appears in the session.
478
+ */
479
+ requestReplan(options?: ReplanOptions | ReplanHints): Promise<void>;
480
+ /**
481
+ * Normalise the requestReplan argument. Accepts either a ReplanOptions
482
+ * object (new API) or a plain Record<string, unknown> (legacy callers
483
+ * that passed hints directly). Distinguishes the two by checking for
484
+ * the presence of ReplanOptions-specific keys.
485
+ */
486
+ private normalizeReplanOptions;
487
+ /** Minimum well-indicated cards before an additive retry is attempted */
488
+ private static readonly MIN_WELL_INDICATED;
489
+ /**
490
+ * Score threshold for considering a card "well-indicated."
491
+ * Cards below this score are treated as fallback filler — present only
492
+ * because no strategy hard-removed them, but likely penalized by one
493
+ * or more filters. Strategy-agnostic: the SessionController doesn't
494
+ * know or care which strategy assigned the score.
495
+ */
496
+ private static readonly WELL_INDICATED_SCORE;
497
+ /**
498
+ * Internal replan execution. Runs the pipeline, builds a new newQ,
499
+ * atomically swaps it in, and triggers hydration for the new contents.
500
+ *
501
+ * If the initial replan produces fewer than MIN_WELL_INDICATED cards that
502
+ * pass all hierarchy filters, one additive retry is attempted — merging
503
+ * any new high-quality candidates into the front of the queue.
504
+ */
505
+ private _executeReplan;
506
+ addTime(seconds: number): void;
507
+ get failedCount(): number;
508
+ toString(): string;
509
+ reportString(): string;
510
+ /**
511
+ * Returns debug information about the current session state.
512
+ * Used by SessionControllerDebug component for runtime inspection.
513
+ */
514
+ getDebugInfo(): {
515
+ api: {
516
+ mode: string;
517
+ description: string;
518
+ };
519
+ reviewQueue: {
520
+ length: number;
521
+ dequeueCount: number;
522
+ items: {
523
+ courseID: any;
524
+ cardID: any;
525
+ status: any;
526
+ }[];
527
+ };
528
+ newQueue: {
529
+ length: number;
530
+ dequeueCount: number;
531
+ items: {
532
+ courseID: any;
533
+ cardID: any;
534
+ status: any;
535
+ }[];
536
+ };
537
+ failedQueue: {
538
+ length: number;
539
+ dequeueCount: number;
540
+ items: {
541
+ courseID: any;
542
+ cardID: any;
543
+ status: any;
544
+ }[];
545
+ };
546
+ hydratedCache: {
547
+ count: number;
548
+ cardIds: string[];
549
+ };
550
+ replan: {
551
+ inProgress: boolean;
552
+ suppressQualityReplan: boolean;
553
+ defaultBatchLimit: number;
554
+ minCardsGuarantee: number;
555
+ };
556
+ };
557
+ /**
558
+ * Fetch content using the getWeightedCards API and mix across sources.
559
+ *
560
+ * This method:
561
+ * 1. Fetches weighted cards from each source
562
+ * 2. Fetches full review data (we need ScheduledCard fields for queue)
563
+ * 3. Uses SourceMixer to balance content across sources
564
+ * 4. Populates review and new card queues with mixed results
565
+ */
566
+ /**
567
+ * Fetch weighted content from all sources and populate session queues.
568
+ *
569
+ * @param options.replan - If true, this is a mid-session replan rather than
570
+ * initial session setup. Skips review queue population (avoiding duplicates),
571
+ * atomically replaces newQ contents, and treats empty results as non-fatal.
572
+ * @param options.additive - If true (replan only), merge new high-quality
573
+ * candidates into the front of the existing newQ instead of replacing it.
574
+ * @returns Number of "well-indicated" cards (passed all hierarchy filters)
575
+ * in the new content. Returns -1 if no content was loaded.
576
+ */
577
+ private getWeightedContent;
578
+ /**
579
+ * Returns items that should be pre-hydrated.
580
+ * Deterministic: top N items from each queue to ensure coverage.
581
+ * Failed queue items will typically already be hydrated (from initial render).
582
+ */
583
+ private _getItemsToHydrate;
584
+ /**
585
+ * Selects the next item to present to the user.
586
+ * Nondeterministic: uses probability to balance between queues based on session state.
587
+ */
588
+ private _selectNextItemToHydrate;
589
+ nextCard(action?: SessionAction): Promise<HydratedCard<TView> | null>;
590
+ /**
591
+ * Public API for processing user responses to cards.
592
+ * @param cardRecord User's response record
593
+ * @param cardHistory Promise resolving to the card's history
594
+ * @param courseRegistrationDoc User's course registration document
595
+ * @param currentCard Current study session record
596
+ * @param courseId Course identifier
597
+ * @param cardId Card identifier
598
+ * @param maxAttemptsPerView Maximum attempts allowed per view
599
+ * @param maxSessionViews Maximum session views for this card
600
+ * @param sessionViews Current number of session views
601
+ * @returns ResponseResult with navigation and UI instructions
602
+ */
603
+ submitResponse(cardRecord: CardRecord, cardHistory: Promise<CardHistory<CardRecord>>, courseRegistrationDoc: CourseRegistrationDoc, currentCard: StudySessionRecord, courseId: string, cardId: string, maxAttemptsPerView: number, maxSessionViews: number, sessionViews: number): Promise<ResponseResult>;
604
+ private dismissCurrentCard;
605
+ /**
606
+ * Remove an item from its source queue after consumption by nextCard().
607
+ */
608
+ private removeItemFromQueue;
609
+ /**
610
+ * End the session and record learning outcomes.
611
+ *
612
+ * This method aggregates all responses from the session and records a
613
+ * UserOutcomeRecord if evolutionary orchestration is enabled.
614
+ */
615
+ endSession(): Promise<void>;
616
+ }
617
+
168
618
  /**
169
619
  * A StudyContentSource that filters cards based on tag inclusion/exclusion.
170
620
  *
@@ -199,7 +649,7 @@ declare class TagFilteredContentSource implements StudyContentSource {
199
649
  * @param limit - Maximum number of cards to return
200
650
  * @returns Cards sorted by score descending (all scores = 1.0)
201
651
  */
202
- getWeightedCards(limit: number): Promise<WeightedCard[]>;
652
+ getWeightedCards(limit: number): Promise<GeneratorResult>;
203
653
  /**
204
654
  * Clears the cached resolved card IDs.
205
655
  * Call this if the underlying tag data may have changed during a session.
@@ -652,4 +1102,4 @@ interface CouchDbUserDoc extends PouchDB.Authentication.User {
652
1102
  entitlements: UserEntitlements;
653
1103
  }
654
1104
 
655
- export { type AggregatedDocument, type AttachmentUploadResult, type CardPresentation, type CouchDbUserDoc, CourseDBInterface, CourseLookup, type CustomQuestionsData, DEFAULT_MIGRATION_OPTIONS, type DataLayerConfig, DataLayerProvider, type DocumentCounts, ENV, type Entitlement, FileSystemAdapter, type MigrationOptions, type MigrationResult, type MixerCardInfo, type MixerRunReport, NOT_SET, type ProcessedDataShape, type ProcessedQuestionData, type QueueSnapshot, type RestoreProgress, type SessionRunReport, SourceBatch, type SourceSelectionBreakdown, type SourceSummary, StaticCourseManifest, type StaticCourseValidation, StaticToCouchDBMigrator, StudyContentSource, TagFilteredContentSource, type UserAccountStatus, UserDBInterface, type UserEntitlements, type ValidationIssue, type ValidationResult, WeightedCard, _resetDataLayer, captureMixerRun, endSessionTracking, ensureAppDataDirectory, getAppDataDirectory, getDataLayer, getDbPath, initializeDataDirectory, initializeDataLayer, isDataShapeRegistered, isDataShapeSchemaAvailable, isQuestionTypeRegistered, mixerDebugAPI, mountMixerDebugger, mountSessionDebugger, processCustomQuestionsData, recordCardPresentation, registerBlanksCard, registerCustomQuestionTypes, registerDataShape, registerQuestionType, registerSeedData, removeCustomQuestionTypes, removeDataShape, removeQuestionType, sessionDebugAPI, snapshotQueues, startSessionTracking, validateMigration, validateStaticCourse };
1105
+ export { type AggregatedDocument, type AttachmentUploadResult, CardHistory, type CardPresentation, CardRecord, type CouchDbUserDoc, CourseDBInterface, CourseLookup, CourseRegistrationDoc, type CustomQuestionsData, DEFAULT_MIGRATION_OPTIONS, type DataLayerConfig, DataLayerProvider, type DocumentCounts, ENV, type Entitlement, FileSystemAdapter, GeneratorResult, Loggable, type MigrationOptions, type MigrationResult, type MixerCardInfo, type MixerRunReport, NOT_SET, type ProcessedDataShape, type ProcessedQuestionData, type QueueSnapshot, QuotaRoundRobinMixer, ReplanHints, type ReplanOptions, type ResponseResult, type RestoreProgress, type SessionAction, SessionController, type SessionRunReport, type SourceBatch, type SourceMixer, type SourceSelectionBreakdown, type SourceSummary, StaticCourseManifest, type StaticCourseValidation, StaticToCouchDBMigrator, StudyContentSource, StudySessionItem, type StudySessionRecord, TagFilteredContentSource, type UserAccountStatus, UserDBInterface, type UserEntitlements, type ValidationIssue, type ValidationResult, WeightedCard, _resetDataLayer, captureMixerRun, endSessionTracking, ensureAppDataDirectory, getAppDataDirectory, getDataLayer, getDbPath, initializeDataDirectory, initializeDataLayer, isDataShapeRegistered, isDataShapeSchemaAvailable, isQuestionTypeRegistered, mixerDebugAPI, mountMixerDebugger, mountSessionDebugger, processCustomQuestionsData, recordCardPresentation, registerBlanksCard, registerCustomQuestionTypes, registerDataShape, registerQuestionType, registerSeedData, removeCustomQuestionTypes, removeDataShape, removeQuestionType, sessionDebugAPI, snapshotQueues, startSessionTracking, validateMigration, validateStaticCourse };