@vue-skuilder/db 0.2.7 → 0.2.8

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.
@@ -340,6 +340,37 @@ declare const DIVERSITY_FLOOR = 0.3;
340
340
  */
341
341
  declare function diversityRerank(cards: WeightedCard[], opts?: DiversityRerankOptions): WeightedCard[];
342
342
 
343
+ /**
344
+ * A navigation pipeline that runs a generator and applies filters sequentially.
345
+ *
346
+ * Implements StudyContentSource for backward compatibility with SessionController.
347
+ *
348
+ * ## Usage
349
+ *
350
+ * ```typescript
351
+ * const pipeline = new Pipeline(
352
+ * compositeGenerator, // or single generator
353
+ * [eloDistanceFilter, interferenceFilter],
354
+ * user,
355
+ * course
356
+ * );
357
+ *
358
+ * const cards = await pipeline.getWeightedCards(20);
359
+ * ```
360
+ */
361
+ /**
362
+ * Narrow capability surface for out-of-band, commit-free reads against a live
363
+ * pipeline (see {@link getActivePipeline}). Kept minimal on purpose — consumers
364
+ * get the forecast capability, not the whole `Pipeline` class.
365
+ */
366
+ interface PipelineForecaster {
367
+ forecast(opts?: {
368
+ hints?: ReplanHints;
369
+ unseenOnly?: boolean;
370
+ threshold?: number;
371
+ limit?: number;
372
+ }): Promise<WeightedCard[]>;
373
+ }
343
374
  /**
344
375
  * Diagnosis of the full card space for the current user.
345
376
  */
@@ -361,6 +392,13 @@ interface CardSpaceDiagnosis {
361
392
  elapsedMs: number;
362
393
  }
363
394
 
395
+ /**
396
+ * The most recently constructed pipeline for the current session, or null if
397
+ * none has been built yet. This is the supported, non-debug accessor for
398
+ * out-of-band reads against the live pipeline (e.g. a commit-free
399
+ * `forecast()`), replacing reach-ins through `window.skuilder.pipeline`.
400
+ */
401
+ declare function getActivePipeline(): PipelineForecaster | null;
364
402
  /**
365
403
  * Summary of a single generator's contribution.
366
404
  */
@@ -742,4 +780,4 @@ declare const userDBDebugAPI: {
742
780
  */
743
781
  declare function mountUserDBDebugger(): void;
744
782
 
745
- export { type BulkCardProcessorConfig, type CardFilter, type CardFilterFactory, CardHistory, CardRecord, CourseDBInterface, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, type DiversityRerankOptions, DocType, DocTypePrefixes, type FilterContext, type FilterImpact, type GeneratorSummary, type GradientObservation, type GradientResult, type ImportResult, LearnableWeight, Loggable, OrchestrationContext, type PeriodUpdateInput, type PeriodUpdateResult, type PipelineRunReport, QuestionRecord, ReplanHints, type SignalConfig, StrategyContribution, type StrategyLearningState, type StrategyStateDoc, type StrategyStateId, UserDBInterface, UserOutcomeRecord, WeightedCard, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig };
783
+ export { type BulkCardProcessorConfig, type CardFilter, type CardFilterFactory, CardHistory, CardRecord, CourseDBInterface, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, type DiversityRerankOptions, DocType, DocTypePrefixes, type FilterContext, type FilterImpact, type GeneratorSummary, type GradientObservation, type GradientResult, type ImportResult, LearnableWeight, Loggable, OrchestrationContext, type PeriodUpdateInput, type PeriodUpdateResult, type PipelineForecaster, type PipelineRunReport, QuestionRecord, ReplanHints, type SignalConfig, StrategyContribution, type StrategyLearningState, type StrategyStateDoc, type StrategyStateId, UserDBInterface, UserOutcomeRecord, WeightedCard, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getActivePipeline, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig };
@@ -340,6 +340,37 @@ declare const DIVERSITY_FLOOR = 0.3;
340
340
  */
341
341
  declare function diversityRerank(cards: WeightedCard[], opts?: DiversityRerankOptions): WeightedCard[];
342
342
 
343
+ /**
344
+ * A navigation pipeline that runs a generator and applies filters sequentially.
345
+ *
346
+ * Implements StudyContentSource for backward compatibility with SessionController.
347
+ *
348
+ * ## Usage
349
+ *
350
+ * ```typescript
351
+ * const pipeline = new Pipeline(
352
+ * compositeGenerator, // or single generator
353
+ * [eloDistanceFilter, interferenceFilter],
354
+ * user,
355
+ * course
356
+ * );
357
+ *
358
+ * const cards = await pipeline.getWeightedCards(20);
359
+ * ```
360
+ */
361
+ /**
362
+ * Narrow capability surface for out-of-band, commit-free reads against a live
363
+ * pipeline (see {@link getActivePipeline}). Kept minimal on purpose — consumers
364
+ * get the forecast capability, not the whole `Pipeline` class.
365
+ */
366
+ interface PipelineForecaster {
367
+ forecast(opts?: {
368
+ hints?: ReplanHints;
369
+ unseenOnly?: boolean;
370
+ threshold?: number;
371
+ limit?: number;
372
+ }): Promise<WeightedCard[]>;
373
+ }
343
374
  /**
344
375
  * Diagnosis of the full card space for the current user.
345
376
  */
@@ -361,6 +392,13 @@ interface CardSpaceDiagnosis {
361
392
  elapsedMs: number;
362
393
  }
363
394
 
395
+ /**
396
+ * The most recently constructed pipeline for the current session, or null if
397
+ * none has been built yet. This is the supported, non-debug accessor for
398
+ * out-of-band reads against the live pipeline (e.g. a commit-free
399
+ * `forecast()`), replacing reach-ins through `window.skuilder.pipeline`.
400
+ */
401
+ declare function getActivePipeline(): PipelineForecaster | null;
364
402
  /**
365
403
  * Summary of a single generator's contribution.
366
404
  */
@@ -742,4 +780,4 @@ declare const userDBDebugAPI: {
742
780
  */
743
781
  declare function mountUserDBDebugger(): void;
744
782
 
745
- export { type BulkCardProcessorConfig, type CardFilter, type CardFilterFactory, CardHistory, CardRecord, CourseDBInterface, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, type DiversityRerankOptions, DocType, DocTypePrefixes, type FilterContext, type FilterImpact, type GeneratorSummary, type GradientObservation, type GradientResult, type ImportResult, LearnableWeight, Loggable, OrchestrationContext, type PeriodUpdateInput, type PeriodUpdateResult, type PipelineRunReport, QuestionRecord, ReplanHints, type SignalConfig, StrategyContribution, type StrategyLearningState, type StrategyStateDoc, type StrategyStateId, UserDBInterface, UserOutcomeRecord, WeightedCard, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig };
783
+ export { type BulkCardProcessorConfig, type CardFilter, type CardFilterFactory, CardHistory, CardRecord, CourseDBInterface, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, type DiversityRerankOptions, DocType, DocTypePrefixes, type FilterContext, type FilterImpact, type GeneratorSummary, type GradientObservation, type GradientResult, type ImportResult, LearnableWeight, Loggable, OrchestrationContext, type PeriodUpdateInput, type PeriodUpdateResult, type PipelineForecaster, type PipelineRunReport, QuestionRecord, ReplanHints, type SignalConfig, StrategyContribution, type StrategyLearningState, type StrategyStateDoc, type StrategyStateId, UserDBInterface, UserOutcomeRecord, WeightedCard, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getActivePipeline, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig };
@@ -814,6 +814,7 @@ __export(PipelineDebugger_exports, {
814
814
  buildRunReport: () => buildRunReport,
815
815
  captureRun: () => captureRun,
816
816
  clearRunHistory: () => clearRunHistory,
817
+ getActivePipeline: () => getActivePipeline,
817
818
  mountPipelineDebugger: () => mountPipelineDebugger,
818
819
  pipelineDebugAPI: () => pipelineDebugAPI,
819
820
  registerPipelineForDebug: () => registerPipelineForDebug
@@ -821,6 +822,9 @@ __export(PipelineDebugger_exports, {
821
822
  function registerPipelineForDebug(pipeline) {
822
823
  _activePipeline = pipeline;
823
824
  }
825
+ function getActivePipeline() {
826
+ return _activePipeline;
827
+ }
824
828
  function clearRunHistory() {
825
829
  runHistory.length = 0;
826
830
  }
@@ -4853,6 +4857,68 @@ var init_Pipeline = __esm({
4853
4857
  // ---------------------------------------------------------------------------
4854
4858
  // Card-space diagnostic
4855
4859
  // ---------------------------------------------------------------------------
4860
+ /**
4861
+ * Commit-free forecast: score the user's full card space through the filter
4862
+ * chain and return the cards that are currently *reachable* (score >=
4863
+ * threshold), optionally nudged by caller-supplied hints and/or restricted
4864
+ * to cards the user hasn't seen yet.
4865
+ *
4866
+ * This is a GENERIC primitive — it returns scored, tag-hydrated cards and
4867
+ * stops there. It has no knowledge of any particular tag convention; callers
4868
+ * decide what the surviving cards mean (e.g. filter to their own "intro"
4869
+ * tag family). Nothing is written and no session is started.
4870
+ *
4871
+ * The optional `hints` are the "out-of-band kick": they run through the same
4872
+ * {@link applyHints} path a live replan uses, so the two semantics carry over —
4873
+ * - `boostTags`/`boostCards` reweight *within* gating (a gated score-0 card
4874
+ * stays out), and
4875
+ * - `requireTags`/`requireCards` inject from the full pre-filter pool,
4876
+ * *bypassing* gating (use when you want a card regardless of reachability).
4877
+ * Note `unseenOnly` is applied LAST, so it can drop a `require`d card that the
4878
+ * user has already seen — pass `unseenOnly: false` if that matters.
4879
+ *
4880
+ * Cost note: like {@link diagnoseCardSpace}, this scans every card through the
4881
+ * filters, so it's heavier than a normal replan. Intended for one-shot
4882
+ * out-of-band use (e.g. a session-end "what's next" snapshot), not the hot path.
4883
+ *
4884
+ * @param opts.hints Optional ephemeral hints to apply after the filter chain.
4885
+ * @param opts.unseenOnly Only return cards the user hasn't encountered (default true).
4886
+ * @param opts.threshold Min score to count as reachable (default 0.10).
4887
+ * @param opts.limit Optional cap on results (already sorted desc).
4888
+ */
4889
+ async forecast(opts) {
4890
+ const threshold = opts?.threshold ?? 0.1;
4891
+ const unseenOnly = opts?.unseenOnly ?? true;
4892
+ const courseId = this.course.getCourseID();
4893
+ const allCardIds = await this.course.getAllCardIds();
4894
+ let cards = allCardIds.map((cardId) => ({
4895
+ cardId,
4896
+ courseId,
4897
+ score: 1,
4898
+ provenance: []
4899
+ }));
4900
+ cards = await this.hydrateTags(cards);
4901
+ const fullPool = cards.slice();
4902
+ const context = await this.buildContext();
4903
+ for (const filter of this.filters) {
4904
+ cards = await filter.transform(cards, context);
4905
+ }
4906
+ if (opts?.hints) {
4907
+ cards = this.applyHints(cards, opts.hints, fullPool);
4908
+ }
4909
+ cards = cards.filter((c) => c.score >= threshold);
4910
+ if (unseenOnly) {
4911
+ let encountered;
4912
+ try {
4913
+ encountered = new Set(await this.user.getSeenCards(courseId));
4914
+ } catch {
4915
+ encountered = /* @__PURE__ */ new Set();
4916
+ }
4917
+ cards = cards.filter((c) => !encountered.has(c.cardId));
4918
+ }
4919
+ cards.sort((a, b) => b.score - a.score);
4920
+ return opts?.limit ? cards.slice(0, opts.limit) : cards;
4921
+ }
4856
4922
  /**
4857
4923
  * Scan every card in the course through the filter chain and report
4858
4924
  * how many are "well indicated" (score >= threshold) for the current user.
@@ -5150,6 +5216,7 @@ __export(navigators_exports, {
5150
5216
  NavigatorRoles: () => NavigatorRoles,
5151
5217
  Navigators: () => Navigators,
5152
5218
  diversityRerank: () => diversityRerank,
5219
+ getActivePipeline: () => getActivePipeline,
5153
5220
  getCardOrigin: () => getCardOrigin,
5154
5221
  getRegisteredNavigator: () => getRegisteredNavigator,
5155
5222
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
@@ -8261,6 +8328,7 @@ __export(core_exports, {
8261
8328
  createOrchestrationContext: () => createOrchestrationContext,
8262
8329
  diversityRerank: () => diversityRerank,
8263
8330
  docIsDeleted: () => docIsDeleted,
8331
+ getActivePipeline: () => getActivePipeline,
8264
8332
  getCardHistoryID: () => getCardHistoryID,
8265
8333
  getCardOrigin: () => getCardOrigin,
8266
8334
  getDefaultLearnableWeight: () => getDefaultLearnableWeight,
@@ -8329,6 +8397,7 @@ init_core();
8329
8397
  createOrchestrationContext,
8330
8398
  diversityRerank,
8331
8399
  docIsDeleted,
8400
+ getActivePipeline,
8332
8401
  getCardHistoryID,
8333
8402
  getCardOrigin,
8334
8403
  getDefaultLearnableWeight,