@vue-skuilder/db 0.2.2 → 0.2.3

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 (39) hide show
  1. package/dist/{contentSource-Ht3N2f-y.d.ts → contentSource-Cplhv3bJ.d.ts} +1 -1
  2. package/dist/{contentSource-BMlMwSiG.d.cts → contentSource-kI9_jwTu.d.cts} +1 -1
  3. package/dist/core/index.d.cts +5 -5
  4. package/dist/core/index.d.ts +5 -5
  5. package/dist/core/index.js +2 -1
  6. package/dist/core/index.js.map +1 -1
  7. package/dist/core/index.mjs +2 -1
  8. package/dist/core/index.mjs.map +1 -1
  9. package/dist/{dataLayerProvider-BEqB8VBR.d.cts → dataLayerProvider-CiA2Rr0v.d.cts} +1 -1
  10. package/dist/{dataLayerProvider-DObSXjnf.d.ts → dataLayerProvider-DrBqOUa3.d.ts} +1 -1
  11. package/dist/impl/couch/index.d.cts +3 -3
  12. package/dist/impl/couch/index.d.ts +3 -3
  13. package/dist/impl/couch/index.js +2 -1
  14. package/dist/impl/couch/index.js.map +1 -1
  15. package/dist/impl/couch/index.mjs +2 -1
  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 +2 -1
  20. package/dist/impl/static/index.js.map +1 -1
  21. package/dist/impl/static/index.mjs +2 -1
  22. package/dist/impl/static/index.mjs.map +1 -1
  23. package/dist/{index-BWvO-_rJ.d.ts → index-BLLT5BYE.d.ts} +1 -1
  24. package/dist/{index-Ba7hYbHj.d.cts → index-k9NFHpS1.d.cts} +1 -1
  25. package/dist/index.d.cts +164 -10
  26. package/dist/index.d.ts +164 -10
  27. package/dist/index.js +141 -8
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +141 -8
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/{types-W8n-B6HG.d.cts → types-BFUa1pa3.d.cts} +1 -1
  32. package/dist/{types-CJrLM1Ew.d.ts → types-CHgpWQAY.d.ts} +1 -1
  33. package/dist/{types-legacy-JXDxinpU.d.cts → types-legacy-4tlwHnXo.d.cts} +1 -1
  34. package/dist/{types-legacy-JXDxinpU.d.ts → types-legacy-4tlwHnXo.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 +3 -3
  38. package/src/core/navigators/Pipeline.ts +1 -1
  39. package/src/study/SessionController.ts +262 -13
@@ -1,4 +1,4 @@
1
- import { P as PackerConfig, a as PackedCourseData, S as StaticCourseManifest } from './types-CJrLM1Ew.js';
1
+ import { P as PackerConfig, a as PackedCourseData, S as StaticCourseManifest } from './types-CHgpWQAY.js';
2
2
 
3
3
  /**
4
4
  * Abstraction for file system operations needed by the migrator.
@@ -1,4 +1,4 @@
1
- import { P as PackerConfig, a as PackedCourseData, S as StaticCourseManifest } from './types-W8n-B6HG.cjs';
1
+ import { P as PackerConfig, a as PackedCourseData, S as StaticCourseManifest } from './types-BFUa1pa3.cjs';
2
2
 
3
3
  /**
4
4
  * Abstraction for file system operations needed by the migrator.
package/dist/index.d.cts CHANGED
@@ -1,15 +1,15 @@
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-BMlMwSiG.cjs';
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-BMlMwSiG.cjs';
3
- import { D as DataLayerProvider } from './dataLayerProvider-BEqB8VBR.cjs';
4
- import { C as CardHistory, c as CardRecord } from './types-legacy-JXDxinpU.cjs';
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.cjs';
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-kI9_jwTu.cjs';
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-kI9_jwTu.cjs';
3
+ import { D as DataLayerProvider } from './dataLayerProvider-CiA2Rr0v.cjs';
4
+ import { C as CardHistory, c as CardRecord, d as QuestionRecord } from './types-legacy-4tlwHnXo.cjs';
5
+ export { e as CardData, f as CourseListData, h as DataShapeData, g as DisplayableData, D as DocType, b as DocTypePrefixes, F as Field, G as GuestUsername, Q as QualifiedCardID, i as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from './types-legacy-4tlwHnXo.cjs';
6
6
  import { Loggable } from './core/index.cjs';
7
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.cjs';
8
8
  import { TaggedPerformance, TagFilter, DataShape, CourseConfig } from '@vue-skuilder/common';
9
- import { S as StaticCourseManifest } from './types-W8n-B6HG.cjs';
10
- export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-W8n-B6HG.cjs';
11
- import { F as FileSystemAdapter } from './index-Ba7hYbHj.cjs';
12
- export { C as CouchDBToStaticPacker, a as FileStats, b as FileSystemError } from './index-Ba7hYbHj.cjs';
9
+ import { S as StaticCourseManifest } from './types-BFUa1pa3.cjs';
10
+ export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-BFUa1pa3.cjs';
11
+ import { F as FileSystemAdapter } from './index-k9NFHpS1.cjs';
12
+ export { C as CouchDBToStaticPacker, a as FileStats, b as FileSystemError } from './index-k9NFHpS1.cjs';
13
13
  import 'moment';
14
14
 
15
15
  /**
@@ -318,6 +318,28 @@ declare class QuotaRoundRobinMixer implements SourceMixer {
318
318
  interface ReplanOptions {
319
319
  /** Scoring hints forwarded to the pipeline (boost/exclude/require). */
320
320
  hints?: ReplanHints;
321
+ /**
322
+ * Session-durable scoring hints. Unlike `hints` (one-shot, applied to
323
+ * exactly the run this replan triggers), `sessionHints` are stashed on
324
+ * the controller and re-merged into *every* subsequent pipeline run for
325
+ * the remainder of the session — including the bare auto-replans
326
+ * (depletion/quality) that carry no caller hints, and the wedge-breaker.
327
+ *
328
+ * Use for "emphasis that should outlive a single queue rebuild" — e.g.
329
+ * boosting a just-failed concept tag, or a post-lesson concept boost set
330
+ * at session start. Without this, a one-shot `hints` boost evaporates on
331
+ * the next replan and the freshly-rebuilt (replace-mode) queue clobbers
332
+ * whatever it surfaced.
333
+ *
334
+ * Semantics (KISS): setting `sessionHints` *replaces* the prior session
335
+ * hints wholesale (caller beware — no accumulation, no decay). They live
336
+ * until session end or until explicitly overwritten. Normal usage applies
337
+ * a fixed boost, so repeated identical requests are no-ops.
338
+ *
339
+ * Merged with per-run `hints` via the pipeline's `mergeHints` (boosts
340
+ * multiply, require/exclude lists concatenate).
341
+ */
342
+ sessionHints?: ReplanHints;
321
343
  /**
322
344
  * Maximum number of new cards to return from the pipeline.
323
345
  * Default: 20 (the standard session batch size).
@@ -369,6 +391,58 @@ interface ResponseResult {
369
391
  performanceScore?: number;
370
392
  shouldClearFeedbackShadow: boolean;
371
393
  }
394
+ /**
395
+ * Read-only snapshot of a single processed response, handed to every
396
+ * registered {@link OutcomeObserver} after ELO/SRS have been recorded.
397
+ *
398
+ * Only emitted for question records (non-question dismisses are skipped).
399
+ */
400
+ interface SessionOutcome {
401
+ /** The user's response. Includes `isCorrect`, `performance`, `priorAttemps`. */
402
+ readonly record: QuestionRecord;
403
+ /**
404
+ * The card that was answered, including its `tags` — the primary key an
405
+ * observer matches against (e.g. `gpc:exercise:*`). `card_elo` reflects
406
+ * pre-update state; the ELO write for this response is already in flight.
407
+ */
408
+ readonly card: StudySessionRecord['card'];
409
+ /** The navigation decision produced for this response (read-only). */
410
+ readonly result: Readonly<ResponseResult>;
411
+ }
412
+ /**
413
+ * The narrow capability surface handed to an {@link OutcomeObserver}. This is
414
+ * the *only* way an observer can affect the session — it cannot touch ELO,
415
+ * the queues, the timer, or mutate the `ResponseResult`. A misbehaving
416
+ * observer degrades to "wrong boost", never "corrupted session".
417
+ */
418
+ interface SessionControls {
419
+ /** Current session-durable hints, or null. For read-modify-write. */
420
+ getSessionHints(): ReplanHints | null;
421
+ /** Replace the session-durable hints wholesale (no decay). */
422
+ setSessionHints(hints: ReplanHints | null): void;
423
+ /**
424
+ * Merge `hints` into the existing session-durable hints via the pipeline's
425
+ * `mergeHints` (boosts multiply, require/exclude lists concat-dedup).
426
+ * Convenience for the common "add a boost on top of what's there" case.
427
+ * Note: multiplicative + no decay — clamp boost factors yourself if a
428
+ * repeatedly-failed tag could compound unboundedly.
429
+ */
430
+ mergeSessionHints(hints: ReplanHints): void;
431
+ /** Request a replan (e.g. `{ mode: 'merge' }` for immediate visibility). */
432
+ requestReplan(opts?: ReplanOptions): Promise<void>;
433
+ }
434
+ /**
435
+ * A consumer-supplied hook invoked after each question response is processed.
436
+ *
437
+ * Fires on *every* question response (gate inside on `record.isCorrect` /
438
+ * `result.nextCardAction` as needed). Awaited but isolated: a throwing
439
+ * observer is caught and logged, never wedging the session. Keep the
440
+ * synchronous body cheap and `void` any long work (e.g. a triggered replan)
441
+ * so you don't stall navigation.
442
+ *
443
+ * Registered via `StudySessionConfig.outcomeObservers` → constructor options.
444
+ */
445
+ type OutcomeObserver = (outcome: SessionOutcome, controls: SessionControls) => void | Promise<void>;
372
446
  interface SessionServices {
373
447
  response: ResponseProcessor;
374
448
  }
@@ -427,6 +501,32 @@ declare class SessionController<TView = unknown> extends Loggable {
427
501
  * each nextCard() draw. Set by replans that include `minFollowUpCards`.
428
502
  */
429
503
  private _minCardsGuarantee;
504
+ /**
505
+ * Session-durable scoring hints. Re-merged into every pipeline run for
506
+ * the rest of the session (initial plan + every replan, including bare
507
+ * auto-replans and the wedge-breaker), via `_applyHintsToSources`.
508
+ *
509
+ * Set by `setSessionHints()` (e.g. session-start post-lesson boost) or by
510
+ * any replan carrying `ReplanOptions.sessionHints` (e.g. a just-failed
511
+ * concept boost). Replace semantics, no decay — lives until overwritten
512
+ * or session end. See `ReplanOptions.sessionHints` for rationale.
513
+ *
514
+ * Note: the controller-managed auto-excludes (current card, session
515
+ * record, imminent draw) are intentionally NOT folded in here — those are
516
+ * recomputed per-run in `_runReplan` and would otherwise go stale.
517
+ */
518
+ private _sessionHints;
519
+ /**
520
+ * Consumer-supplied hooks invoked after each question response is processed.
521
+ * Seeded from constructor options (threaded from
522
+ * `StudySessionConfig.outcomeObservers`). See {@link OutcomeObserver}.
523
+ */
524
+ private _outcomeObservers;
525
+ /**
526
+ * Lazily-built, stable capability object handed to observers. Bound to
527
+ * `this`; constructed once so observers can rely on referential identity.
528
+ */
529
+ private _sessionControls;
430
530
  private startTime;
431
531
  private endTime;
432
532
  private _secondsRemaining;
@@ -452,6 +552,7 @@ declare class SessionController<TView = unknown> extends Loggable {
452
552
  constructor(sources: StudyContentSource[], time: number, dataLayer: DataLayerProvider, getViewComponent: (viewId: string) => TView, mixer?: SourceMixer, options?: {
453
553
  defaultBatchLimit?: number;
454
554
  initialReviewCap?: number;
555
+ outcomeObservers?: OutcomeObserver[];
455
556
  });
456
557
  private tick;
457
558
  /**
@@ -514,6 +615,59 @@ declare class SessionController<TView = unknown> extends Loggable {
514
615
  * newQ.peek(0) is the imminent draw we need to exclude.
515
616
  */
516
617
  private _runReplan;
618
+ /**
619
+ * Set the session-durable scoring hints (replace semantics, no decay).
620
+ *
621
+ * Unlike a one-shot replan hint, these are re-merged into every pipeline
622
+ * run for the rest of the session — including the initial plan when set
623
+ * before `prepareSession()`, every replan, the bare auto-replans, and the
624
+ * wedge-breaker. Pass `null` to clear.
625
+ *
626
+ * Typical callers:
627
+ * - `StudySession` at session start, threading `StudySessionConfig.initHints`
628
+ * (e.g. a post-lesson concept boost) — so the boost outlives the first
629
+ * queue rebuild instead of being clobbered by the first auto-replan.
630
+ * - A consumer view on a failure, boosting the just-failed concept tag.
631
+ *
632
+ * Does not itself trigger a replan; the next plan/replan picks it up.
633
+ */
634
+ setSessionHints(hints: ReplanHints | null): void;
635
+ /**
636
+ * Read the current session-durable hints (for read-modify-write callers,
637
+ * e.g. an outcome observer that clamps a compounding boost).
638
+ */
639
+ getSessionHints(): ReplanHints | null;
640
+ /**
641
+ * Merge `hints` into the durable session hints via the pipeline's
642
+ * `mergeHints` (boosts multiply, require/exclude lists concat-dedup).
643
+ * Convenience over get-then-set for the common additive case. Note the
644
+ * multiplicative, no-decay semantics — clamp boost factors at the call
645
+ * site if a repeatedly-emphasised tag could compound unboundedly.
646
+ */
647
+ mergeSessionHints(hints: ReplanHints): void;
648
+ /**
649
+ * Merge the durable `_sessionHints` with this run's one-shot hints and
650
+ * push the result to every source for consumption on the next pipeline
651
+ * run. Centralised so the initial plan and all replan paths apply session
652
+ * emphasis identically. No-op when there are no hints of either kind.
653
+ */
654
+ private _applyHintsToSources;
655
+ /**
656
+ * Build (once) the stable capability object handed to outcome observers.
657
+ * Methods are bound to `this`; the object identity is stable across calls
658
+ * so observers may key off it.
659
+ */
660
+ private _getSessionControls;
661
+ /**
662
+ * Notify registered outcome observers about a processed response.
663
+ *
664
+ * Only question records are surfaced (non-question dismisses are skipped).
665
+ * Observers run after ELO/SRS are recorded and before navigation. Each is
666
+ * awaited but isolated in try/catch — a throwing observer is logged and
667
+ * skipped, never wedging the session. Keep observers cheap and `void` any
668
+ * long work (e.g. a triggered replan) to avoid stalling the draw.
669
+ */
670
+ private _notifyOutcomeObservers;
517
671
  /**
518
672
  * Run a replan, bypassing requestReplan()'s coalesce logic.
519
673
  *
@@ -1176,4 +1330,4 @@ interface CouchDbUserDoc extends PouchDB.Authentication.User {
1176
1330
  entitlements: UserEntitlements;
1177
1331
  }
1178
1332
 
1179
- 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 };
1333
+ 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 OutcomeObserver, type ProcessedDataShape, type ProcessedQuestionData, QuestionRecord, type QueueSnapshot, QuotaRoundRobinMixer, ReplanHints, type ReplanOptions, type ResponseResult, type RestoreProgress, type SessionAction, SessionController, type SessionControls, type SessionOutcome, 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 };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,15 @@
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';
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-Cplhv3bJ.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-Cplhv3bJ.js';
3
+ import { D as DataLayerProvider } from './dataLayerProvider-DrBqOUa3.js';
4
+ import { C as CardHistory, c as CardRecord, d as QuestionRecord } from './types-legacy-4tlwHnXo.js';
5
+ export { e as CardData, f as CourseListData, h as DataShapeData, g as DisplayableData, D as DocType, b as DocTypePrefixes, F as Field, G as GuestUsername, Q as QualifiedCardID, i as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from './types-legacy-4tlwHnXo.js';
6
6
  import { Loggable } from './core/index.js';
7
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
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';
9
+ import { S as StaticCourseManifest } from './types-CHgpWQAY.js';
10
+ export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-CHgpWQAY.js';
11
+ import { F as FileSystemAdapter } from './index-BLLT5BYE.js';
12
+ export { C as CouchDBToStaticPacker, a as FileStats, b as FileSystemError } from './index-BLLT5BYE.js';
13
13
  import 'moment';
14
14
 
15
15
  /**
@@ -318,6 +318,28 @@ declare class QuotaRoundRobinMixer implements SourceMixer {
318
318
  interface ReplanOptions {
319
319
  /** Scoring hints forwarded to the pipeline (boost/exclude/require). */
320
320
  hints?: ReplanHints;
321
+ /**
322
+ * Session-durable scoring hints. Unlike `hints` (one-shot, applied to
323
+ * exactly the run this replan triggers), `sessionHints` are stashed on
324
+ * the controller and re-merged into *every* subsequent pipeline run for
325
+ * the remainder of the session — including the bare auto-replans
326
+ * (depletion/quality) that carry no caller hints, and the wedge-breaker.
327
+ *
328
+ * Use for "emphasis that should outlive a single queue rebuild" — e.g.
329
+ * boosting a just-failed concept tag, or a post-lesson concept boost set
330
+ * at session start. Without this, a one-shot `hints` boost evaporates on
331
+ * the next replan and the freshly-rebuilt (replace-mode) queue clobbers
332
+ * whatever it surfaced.
333
+ *
334
+ * Semantics (KISS): setting `sessionHints` *replaces* the prior session
335
+ * hints wholesale (caller beware — no accumulation, no decay). They live
336
+ * until session end or until explicitly overwritten. Normal usage applies
337
+ * a fixed boost, so repeated identical requests are no-ops.
338
+ *
339
+ * Merged with per-run `hints` via the pipeline's `mergeHints` (boosts
340
+ * multiply, require/exclude lists concatenate).
341
+ */
342
+ sessionHints?: ReplanHints;
321
343
  /**
322
344
  * Maximum number of new cards to return from the pipeline.
323
345
  * Default: 20 (the standard session batch size).
@@ -369,6 +391,58 @@ interface ResponseResult {
369
391
  performanceScore?: number;
370
392
  shouldClearFeedbackShadow: boolean;
371
393
  }
394
+ /**
395
+ * Read-only snapshot of a single processed response, handed to every
396
+ * registered {@link OutcomeObserver} after ELO/SRS have been recorded.
397
+ *
398
+ * Only emitted for question records (non-question dismisses are skipped).
399
+ */
400
+ interface SessionOutcome {
401
+ /** The user's response. Includes `isCorrect`, `performance`, `priorAttemps`. */
402
+ readonly record: QuestionRecord;
403
+ /**
404
+ * The card that was answered, including its `tags` — the primary key an
405
+ * observer matches against (e.g. `gpc:exercise:*`). `card_elo` reflects
406
+ * pre-update state; the ELO write for this response is already in flight.
407
+ */
408
+ readonly card: StudySessionRecord['card'];
409
+ /** The navigation decision produced for this response (read-only). */
410
+ readonly result: Readonly<ResponseResult>;
411
+ }
412
+ /**
413
+ * The narrow capability surface handed to an {@link OutcomeObserver}. This is
414
+ * the *only* way an observer can affect the session — it cannot touch ELO,
415
+ * the queues, the timer, or mutate the `ResponseResult`. A misbehaving
416
+ * observer degrades to "wrong boost", never "corrupted session".
417
+ */
418
+ interface SessionControls {
419
+ /** Current session-durable hints, or null. For read-modify-write. */
420
+ getSessionHints(): ReplanHints | null;
421
+ /** Replace the session-durable hints wholesale (no decay). */
422
+ setSessionHints(hints: ReplanHints | null): void;
423
+ /**
424
+ * Merge `hints` into the existing session-durable hints via the pipeline's
425
+ * `mergeHints` (boosts multiply, require/exclude lists concat-dedup).
426
+ * Convenience for the common "add a boost on top of what's there" case.
427
+ * Note: multiplicative + no decay — clamp boost factors yourself if a
428
+ * repeatedly-failed tag could compound unboundedly.
429
+ */
430
+ mergeSessionHints(hints: ReplanHints): void;
431
+ /** Request a replan (e.g. `{ mode: 'merge' }` for immediate visibility). */
432
+ requestReplan(opts?: ReplanOptions): Promise<void>;
433
+ }
434
+ /**
435
+ * A consumer-supplied hook invoked after each question response is processed.
436
+ *
437
+ * Fires on *every* question response (gate inside on `record.isCorrect` /
438
+ * `result.nextCardAction` as needed). Awaited but isolated: a throwing
439
+ * observer is caught and logged, never wedging the session. Keep the
440
+ * synchronous body cheap and `void` any long work (e.g. a triggered replan)
441
+ * so you don't stall navigation.
442
+ *
443
+ * Registered via `StudySessionConfig.outcomeObservers` → constructor options.
444
+ */
445
+ type OutcomeObserver = (outcome: SessionOutcome, controls: SessionControls) => void | Promise<void>;
372
446
  interface SessionServices {
373
447
  response: ResponseProcessor;
374
448
  }
@@ -427,6 +501,32 @@ declare class SessionController<TView = unknown> extends Loggable {
427
501
  * each nextCard() draw. Set by replans that include `minFollowUpCards`.
428
502
  */
429
503
  private _minCardsGuarantee;
504
+ /**
505
+ * Session-durable scoring hints. Re-merged into every pipeline run for
506
+ * the rest of the session (initial plan + every replan, including bare
507
+ * auto-replans and the wedge-breaker), via `_applyHintsToSources`.
508
+ *
509
+ * Set by `setSessionHints()` (e.g. session-start post-lesson boost) or by
510
+ * any replan carrying `ReplanOptions.sessionHints` (e.g. a just-failed
511
+ * concept boost). Replace semantics, no decay — lives until overwritten
512
+ * or session end. See `ReplanOptions.sessionHints` for rationale.
513
+ *
514
+ * Note: the controller-managed auto-excludes (current card, session
515
+ * record, imminent draw) are intentionally NOT folded in here — those are
516
+ * recomputed per-run in `_runReplan` and would otherwise go stale.
517
+ */
518
+ private _sessionHints;
519
+ /**
520
+ * Consumer-supplied hooks invoked after each question response is processed.
521
+ * Seeded from constructor options (threaded from
522
+ * `StudySessionConfig.outcomeObservers`). See {@link OutcomeObserver}.
523
+ */
524
+ private _outcomeObservers;
525
+ /**
526
+ * Lazily-built, stable capability object handed to observers. Bound to
527
+ * `this`; constructed once so observers can rely on referential identity.
528
+ */
529
+ private _sessionControls;
430
530
  private startTime;
431
531
  private endTime;
432
532
  private _secondsRemaining;
@@ -452,6 +552,7 @@ declare class SessionController<TView = unknown> extends Loggable {
452
552
  constructor(sources: StudyContentSource[], time: number, dataLayer: DataLayerProvider, getViewComponent: (viewId: string) => TView, mixer?: SourceMixer, options?: {
453
553
  defaultBatchLimit?: number;
454
554
  initialReviewCap?: number;
555
+ outcomeObservers?: OutcomeObserver[];
455
556
  });
456
557
  private tick;
457
558
  /**
@@ -514,6 +615,59 @@ declare class SessionController<TView = unknown> extends Loggable {
514
615
  * newQ.peek(0) is the imminent draw we need to exclude.
515
616
  */
516
617
  private _runReplan;
618
+ /**
619
+ * Set the session-durable scoring hints (replace semantics, no decay).
620
+ *
621
+ * Unlike a one-shot replan hint, these are re-merged into every pipeline
622
+ * run for the rest of the session — including the initial plan when set
623
+ * before `prepareSession()`, every replan, the bare auto-replans, and the
624
+ * wedge-breaker. Pass `null` to clear.
625
+ *
626
+ * Typical callers:
627
+ * - `StudySession` at session start, threading `StudySessionConfig.initHints`
628
+ * (e.g. a post-lesson concept boost) — so the boost outlives the first
629
+ * queue rebuild instead of being clobbered by the first auto-replan.
630
+ * - A consumer view on a failure, boosting the just-failed concept tag.
631
+ *
632
+ * Does not itself trigger a replan; the next plan/replan picks it up.
633
+ */
634
+ setSessionHints(hints: ReplanHints | null): void;
635
+ /**
636
+ * Read the current session-durable hints (for read-modify-write callers,
637
+ * e.g. an outcome observer that clamps a compounding boost).
638
+ */
639
+ getSessionHints(): ReplanHints | null;
640
+ /**
641
+ * Merge `hints` into the durable session hints via the pipeline's
642
+ * `mergeHints` (boosts multiply, require/exclude lists concat-dedup).
643
+ * Convenience over get-then-set for the common additive case. Note the
644
+ * multiplicative, no-decay semantics — clamp boost factors at the call
645
+ * site if a repeatedly-emphasised tag could compound unboundedly.
646
+ */
647
+ mergeSessionHints(hints: ReplanHints): void;
648
+ /**
649
+ * Merge the durable `_sessionHints` with this run's one-shot hints and
650
+ * push the result to every source for consumption on the next pipeline
651
+ * run. Centralised so the initial plan and all replan paths apply session
652
+ * emphasis identically. No-op when there are no hints of either kind.
653
+ */
654
+ private _applyHintsToSources;
655
+ /**
656
+ * Build (once) the stable capability object handed to outcome observers.
657
+ * Methods are bound to `this`; the object identity is stable across calls
658
+ * so observers may key off it.
659
+ */
660
+ private _getSessionControls;
661
+ /**
662
+ * Notify registered outcome observers about a processed response.
663
+ *
664
+ * Only question records are surfaced (non-question dismisses are skipped).
665
+ * Observers run after ELO/SRS are recorded and before navigation. Each is
666
+ * awaited but isolated in try/catch — a throwing observer is logged and
667
+ * skipped, never wedging the session. Keep observers cheap and `void` any
668
+ * long work (e.g. a triggered replan) to avoid stalling the draw.
669
+ */
670
+ private _notifyOutcomeObservers;
517
671
  /**
518
672
  * Run a replan, bypassing requestReplan()'s coalesce logic.
519
673
  *
@@ -1176,4 +1330,4 @@ interface CouchDbUserDoc extends PouchDB.Authentication.User {
1176
1330
  entitlements: UserEntitlements;
1177
1331
  }
1178
1332
 
1179
- 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 };
1333
+ 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 OutcomeObserver, type ProcessedDataShape, type ProcessedQuestionData, QuestionRecord, type QueueSnapshot, QuotaRoundRobinMixer, ReplanHints, type ReplanOptions, type ResponseResult, type RestoreProgress, type SessionAction, SessionController, type SessionControls, type SessionOutcome, 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 };