@vue-skuilder/db 0.1.16 → 0.1.18
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.
- package/dist/{userDB-DNa0XPtn.d.ts → classroomDB-BgfrVb8d.d.ts} +357 -103
- package/dist/{userDB-BqwxtJ_7.d.mts → classroomDB-CTOenngH.d.cts} +358 -104
- package/dist/core/index.d.cts +230 -0
- package/dist/core/index.d.ts +161 -23
- package/dist/core/index.js +1964 -154
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +1925 -121
- package/dist/core/index.mjs.map +1 -1
- package/dist/{dataLayerProvider-BV5iZqt_.d.ts → dataLayerProvider-CZxC9GtB.d.ts} +1 -1
- package/dist/{dataLayerProvider-VlngD19_.d.mts → dataLayerProvider-D6PoCwS6.d.cts} +1 -1
- package/dist/impl/couch/{index.d.mts → index.d.cts} +46 -5
- package/dist/impl/couch/index.d.ts +44 -3
- package/dist/impl/couch/index.js +1971 -171
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +1933 -134
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/{index.d.mts → index.d.cts} +5 -6
- package/dist/impl/static/index.d.ts +2 -3
- package/dist/impl/static/index.js +1614 -119
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +1585 -92
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/{index-Bmll7Xse.d.mts → index-D-Fa4Smt.d.cts} +1 -1
- package/dist/{index.d.mts → index.d.cts} +97 -13
- package/dist/index.d.ts +90 -6
- package/dist/index.js +2085 -153
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2031 -106
- package/dist/index.mjs.map +1 -1
- package/dist/pouch/index.js +3 -3
- package/dist/{types-Dbp5DaRR.d.mts → types-CzPDLAK6.d.cts} +1 -1
- package/dist/util/packer/{index.d.mts → index.d.cts} +3 -3
- package/dist/util/packer/index.js.map +1 -1
- package/dist/util/packer/index.mjs.map +1 -1
- package/docs/brainstorm-navigation-paradigm.md +369 -0
- package/docs/navigators-architecture.md +265 -0
- package/docs/todo-evolutionary-orchestration.md +310 -0
- package/docs/todo-nominal-tag-types.md +121 -0
- package/docs/todo-pipeline-optimization.md +117 -0
- package/docs/todo-strategy-authoring.md +401 -0
- package/docs/todo-strategy-state-storage.md +278 -0
- package/eslint.config.mjs +1 -1
- package/package.json +9 -4
- package/src/core/interfaces/contentSource.ts +88 -4
- package/src/core/interfaces/navigationStrategyManager.ts +0 -5
- package/src/core/navigators/CompositeGenerator.ts +268 -0
- package/src/core/navigators/Pipeline.ts +205 -0
- package/src/core/navigators/PipelineAssembler.ts +194 -0
- package/src/core/navigators/elo.ts +104 -15
- package/src/core/navigators/filters/eloDistance.ts +132 -0
- package/src/core/navigators/filters/index.ts +6 -0
- package/src/core/navigators/filters/types.ts +115 -0
- package/src/core/navigators/generators/index.ts +2 -0
- package/src/core/navigators/generators/types.ts +107 -0
- package/src/core/navigators/hardcodedOrder.ts +111 -12
- package/src/core/navigators/hierarchyDefinition.ts +266 -0
- package/src/core/navigators/index.ts +345 -3
- package/src/core/navigators/interferenceMitigator.ts +367 -0
- package/src/core/navigators/relativePriority.ts +267 -0
- package/src/core/navigators/srs.ts +195 -0
- package/src/impl/couch/classroomDB.ts +51 -0
- package/src/impl/couch/courseDB.ts +117 -39
- package/src/impl/static/courseDB.ts +0 -4
- package/src/study/SessionController.ts +149 -1
- package/src/study/TagFilteredContentSource.ts +255 -0
- package/src/study/index.ts +1 -0
- package/src/util/dataDirectory.test.ts +51 -22
- package/src/util/logger.ts +0 -1
- package/tests/core/navigators/CompositeGenerator.test.ts +455 -0
- package/tests/core/navigators/Pipeline.test.ts +405 -0
- package/tests/core/navigators/PipelineAssembler.test.ts +351 -0
- package/tests/core/navigators/SRSNavigator.test.ts +344 -0
- package/tests/core/navigators/eloDistanceFilter.test.ts +192 -0
- package/tests/core/navigators/navigators.test.ts +710 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +29 -0
- package/dist/core/index.d.mts +0 -92
- /package/dist/{SyncStrategy-CyATpyLQ.d.mts → SyncStrategy-CyATpyLQ.d.cts} +0 -0
- /package/dist/pouch/{index.d.mts → index.d.cts} +0 -0
- /package/dist/{types-legacy-6ettoclI.d.mts → types-legacy-6ettoclI.d.cts} +0 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { W as WeightedCard, U as UserDBInterface, C as CourseDBInterface } from '../classroomDB-CTOenngH.cjs';
|
|
2
|
+
export { J as ActivityRecord, A as AdminDBInterface, v as AssignedCard, h as AssignedContent, u as AssignedCourse, t as AssignedTag, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, G as ClassroomRegistrationDoc, k as ContentNavigator, q as ContentSourceID, d as CourseInfo, K as CourseRegistration, s as CourseRegistrationDoc, b as CoursesDBInterface, O as NavigatorRole, P as NavigatorRoles, N as Navigators, g as ScheduledCard, H as SessionTrackingData, L as StrategyContribution, j as StudentClassroomDBInterface, i as StudyContentSource, m as StudySessionFailedItem, n as StudySessionFailedNewItem, o as StudySessionFailedReviewItem, l as StudySessionItem, S as StudySessionNewItem, f as StudySessionReviewItem, T as TeacherClassroomDBInterface, I as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, B as UsrCrsDataInterface, M as getCardOrigin, r as getStudySource, R as isFilter, Q as isGenerator, p as isReview } from '../classroomDB-CTOenngH.cjs';
|
|
3
|
+
export { D as DataLayerProvider } from '../dataLayerProvider-D6PoCwS6.cjs';
|
|
4
|
+
import { C as CardHistory, c as CardRecord, i as QuestionRecord } from '../types-legacy-6ettoclI.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, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from '../types-legacy-6ettoclI.cjs';
|
|
6
|
+
import { DataShape, ParsedCard } from '@vue-skuilder/common';
|
|
7
|
+
import 'moment';
|
|
8
|
+
|
|
9
|
+
declare abstract class Loggable {
|
|
10
|
+
protected abstract readonly _className: string;
|
|
11
|
+
protected log(...args: unknown[]): void;
|
|
12
|
+
protected error(...args: unknown[]): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Shared context available to all filters in a pipeline.
|
|
17
|
+
*
|
|
18
|
+
* Built once per getWeightedCards() call and passed to each filter.
|
|
19
|
+
* This avoids repeated lookups for common data like user ELO.
|
|
20
|
+
*/
|
|
21
|
+
interface FilterContext {
|
|
22
|
+
/** User database interface */
|
|
23
|
+
user: UserDBInterface;
|
|
24
|
+
/** Course database interface */
|
|
25
|
+
course: CourseDBInterface;
|
|
26
|
+
/** User's global ELO score for this course */
|
|
27
|
+
userElo: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A filter that transforms a list of weighted cards.
|
|
31
|
+
*
|
|
32
|
+
* Filters are pure transforms - they receive cards and context,
|
|
33
|
+
* and return a modified list of cards. No delegate wrapping,
|
|
34
|
+
* no side effects beyond provenance tracking.
|
|
35
|
+
*
|
|
36
|
+
* ## Implementation Guidelines
|
|
37
|
+
*
|
|
38
|
+
* 1. **Append provenance**: Every filter should add a StrategyContribution
|
|
39
|
+
* entry documenting its decision for each card.
|
|
40
|
+
*
|
|
41
|
+
* 2. **Use multipliers**: Adjust scores by multiplying, not replacing.
|
|
42
|
+
* This ensures filter order doesn't matter.
|
|
43
|
+
*
|
|
44
|
+
* 3. **Score 0 for exclusion**: To exclude a card, set score to 0.
|
|
45
|
+
* Don't filter it out - let provenance show why it was excluded.
|
|
46
|
+
*
|
|
47
|
+
* 4. **Don't sort**: The Pipeline handles final sorting.
|
|
48
|
+
* Filters just transform scores.
|
|
49
|
+
*
|
|
50
|
+
* ## Example Implementation
|
|
51
|
+
*
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const myFilter: CardFilter = {
|
|
54
|
+
* name: 'My Filter',
|
|
55
|
+
* async transform(cards, context) {
|
|
56
|
+
* return cards.map(card => {
|
|
57
|
+
* const multiplier = computeMultiplier(card, context);
|
|
58
|
+
* const newScore = card.score * multiplier;
|
|
59
|
+
* return {
|
|
60
|
+
* ...card,
|
|
61
|
+
* score: newScore,
|
|
62
|
+
* provenance: [...card.provenance, {
|
|
63
|
+
* strategy: 'myFilter',
|
|
64
|
+
* strategyName: 'My Filter',
|
|
65
|
+
* strategyId: 'MY_FILTER',
|
|
66
|
+
* action: multiplier < 1 ? 'penalized' : 'passed',
|
|
67
|
+
* score: newScore,
|
|
68
|
+
* reason: 'Explanation of decision'
|
|
69
|
+
* }]
|
|
70
|
+
* };
|
|
71
|
+
* });
|
|
72
|
+
* }
|
|
73
|
+
* };
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
interface CardFilter {
|
|
77
|
+
/** Human-readable name for this filter */
|
|
78
|
+
name: string;
|
|
79
|
+
/**
|
|
80
|
+
* Transform a list of weighted cards.
|
|
81
|
+
*
|
|
82
|
+
* @param cards - Cards to transform (already scored by generator)
|
|
83
|
+
* @param context - Shared context (user, course, userElo, etc.)
|
|
84
|
+
* @returns Transformed cards with updated scores and provenance
|
|
85
|
+
*/
|
|
86
|
+
transform(cards: WeightedCard[], context: FilterContext): Promise<WeightedCard[]>;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Factory function type for creating filters from configuration.
|
|
90
|
+
*
|
|
91
|
+
* Used by PipelineAssembler to instantiate filters from strategy documents.
|
|
92
|
+
*/
|
|
93
|
+
type CardFilterFactory<TConfig = unknown> = (config: TConfig) => CardFilter;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Context available to generators when producing candidates.
|
|
97
|
+
*
|
|
98
|
+
* Built once per getWeightedCards() call by the Pipeline.
|
|
99
|
+
*/
|
|
100
|
+
interface GeneratorContext {
|
|
101
|
+
/** User database interface */
|
|
102
|
+
user: UserDBInterface;
|
|
103
|
+
/** Course database interface */
|
|
104
|
+
course: CourseDBInterface;
|
|
105
|
+
/** User's global ELO score for this course */
|
|
106
|
+
userElo: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A generator that produces candidate cards with initial scores.
|
|
110
|
+
*
|
|
111
|
+
* Generators are the "source" stage of a navigation pipeline.
|
|
112
|
+
* They query the database for eligible cards and assign initial
|
|
113
|
+
* suitability scores based on their strategy (ELO proximity,
|
|
114
|
+
* review urgency, fixed order, etc.).
|
|
115
|
+
*
|
|
116
|
+
* ## Implementation Guidelines
|
|
117
|
+
*
|
|
118
|
+
* 1. **Create provenance**: Each card should have a provenance entry
|
|
119
|
+
* with action='generated' documenting why it was selected.
|
|
120
|
+
*
|
|
121
|
+
* 2. **Score semantics**: Higher scores = more suitable for presentation.
|
|
122
|
+
* Scores should be in [0, 1] range for composability.
|
|
123
|
+
*
|
|
124
|
+
* 3. **Limit handling**: Respect the limit parameter, but may over-fetch
|
|
125
|
+
* internally if needed for scoring accuracy.
|
|
126
|
+
*
|
|
127
|
+
* 4. **Sort before returning**: Return cards sorted by score descending.
|
|
128
|
+
*
|
|
129
|
+
* ## Example Implementation
|
|
130
|
+
*
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const myGenerator: CardGenerator = {
|
|
133
|
+
* name: 'My Generator',
|
|
134
|
+
* async getWeightedCards(limit, context) {
|
|
135
|
+
* const candidates = await fetchCandidates(context.course, limit);
|
|
136
|
+
* return candidates.map(c => ({
|
|
137
|
+
* cardId: c.id,
|
|
138
|
+
* courseId: context.course.getCourseID(),
|
|
139
|
+
* score: computeScore(c, context),
|
|
140
|
+
* provenance: [{
|
|
141
|
+
* strategy: 'myGenerator',
|
|
142
|
+
* strategyName: 'My Generator',
|
|
143
|
+
* strategyId: 'MY_GENERATOR',
|
|
144
|
+
* action: 'generated',
|
|
145
|
+
* score: computeScore(c, context),
|
|
146
|
+
* reason: 'Explanation of selection'
|
|
147
|
+
* }]
|
|
148
|
+
* }));
|
|
149
|
+
* }
|
|
150
|
+
* };
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
interface CardGenerator {
|
|
154
|
+
/** Human-readable name for this generator */
|
|
155
|
+
name: string;
|
|
156
|
+
/**
|
|
157
|
+
* Produce candidate cards with initial scores.
|
|
158
|
+
*
|
|
159
|
+
* @param limit - Maximum number of cards to return
|
|
160
|
+
* @param context - Shared context (user, course, userElo, etc.)
|
|
161
|
+
* @returns Cards sorted by score descending, with provenance
|
|
162
|
+
*/
|
|
163
|
+
getWeightedCards(limit: number, context: GeneratorContext): Promise<WeightedCard[]>;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Factory function type for creating generators from configuration.
|
|
167
|
+
*
|
|
168
|
+
* Used by PipelineAssembler to instantiate generators from strategy documents.
|
|
169
|
+
*/
|
|
170
|
+
type CardGeneratorFactory<TConfig = unknown> = (config: TConfig) => CardGenerator;
|
|
171
|
+
|
|
172
|
+
declare function areQuestionRecords(h: CardHistory<CardRecord>): h is CardHistory<QuestionRecord>;
|
|
173
|
+
declare function isQuestionRecord(c: CardRecord): c is QuestionRecord;
|
|
174
|
+
declare function getCardHistoryID(courseID: string, cardID: string): PouchDB.Core.DocumentId;
|
|
175
|
+
declare function parseCardHistoryID(id: string): {
|
|
176
|
+
courseID: string;
|
|
177
|
+
cardID: string;
|
|
178
|
+
};
|
|
179
|
+
interface PouchDBError extends Error {
|
|
180
|
+
error?: string;
|
|
181
|
+
reason?: string;
|
|
182
|
+
}
|
|
183
|
+
declare function docIsDeleted(e: PouchDBError): boolean;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Interface representing the result of a bulk import operation for a single card
|
|
187
|
+
*/
|
|
188
|
+
interface ImportResult {
|
|
189
|
+
/** The original text input for the card */
|
|
190
|
+
originalText: string;
|
|
191
|
+
/** Status of the import operation */
|
|
192
|
+
status: 'success' | 'error';
|
|
193
|
+
/** Message describing the result or error */
|
|
194
|
+
message: string;
|
|
195
|
+
/** ID of the newly created card (only for success) */
|
|
196
|
+
cardId?: string;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Configuration for the bulk card processor
|
|
200
|
+
*/
|
|
201
|
+
interface BulkCardProcessorConfig {
|
|
202
|
+
/** The data shape to use for the cards */
|
|
203
|
+
dataShape: DataShape;
|
|
204
|
+
/** The course code used for adding notes */
|
|
205
|
+
courseCode: string;
|
|
206
|
+
/** The username of the current user */
|
|
207
|
+
userName: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Processes multiple cards from bulk text input
|
|
212
|
+
*
|
|
213
|
+
* @param parsedCards - Array of parsed cards to import
|
|
214
|
+
* @param courseDB - Course database interface
|
|
215
|
+
* @param config - Configuration for the card processor
|
|
216
|
+
* @returns Array of import results
|
|
217
|
+
*/
|
|
218
|
+
declare function importParsedCards(parsedCards: ParsedCard[], courseDB: CourseDBInterface, config: BulkCardProcessorConfig): Promise<ImportResult[]>;
|
|
219
|
+
/**
|
|
220
|
+
* Validates the configuration for bulk card processing
|
|
221
|
+
*
|
|
222
|
+
* @param config - Configuration to validate
|
|
223
|
+
* @returns Object with validation result and error message if any
|
|
224
|
+
*/
|
|
225
|
+
declare function validateProcessorConfig(config: Partial<BulkCardProcessorConfig>): {
|
|
226
|
+
isValid: boolean;
|
|
227
|
+
errorMessage?: string;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export { type BulkCardProcessorConfig, type CardFilter, type CardFilterFactory, type CardGenerator, type CardGeneratorFactory, CardHistory, CardRecord, CourseDBInterface, type FilterContext, type GeneratorContext, type ImportResult, Loggable, QuestionRecord, UserDBInterface, WeightedCard, areQuestionRecords, docIsDeleted, getCardHistoryID, importParsedCards, isQuestionRecord, parseCardHistoryID, validateProcessorConfig };
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
export { D as DataLayerProvider } from '../dataLayerProvider-
|
|
1
|
+
import { W as WeightedCard, U as UserDBInterface, C as CourseDBInterface } from '../classroomDB-BgfrVb8d.js';
|
|
2
|
+
export { J as ActivityRecord, A as AdminDBInterface, v as AssignedCard, h as AssignedContent, u as AssignedCourse, t as AssignedTag, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, G as ClassroomRegistrationDoc, k as ContentNavigator, q as ContentSourceID, d as CourseInfo, K as CourseRegistration, s as CourseRegistrationDoc, b as CoursesDBInterface, O as NavigatorRole, P as NavigatorRoles, N as Navigators, g as ScheduledCard, H as SessionTrackingData, L as StrategyContribution, j as StudentClassroomDBInterface, i as StudyContentSource, m as StudySessionFailedItem, n as StudySessionFailedNewItem, o as StudySessionFailedReviewItem, l as StudySessionItem, S as StudySessionNewItem, f as StudySessionReviewItem, T as TeacherClassroomDBInterface, I as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, B as UsrCrsDataInterface, M as getCardOrigin, r as getStudySource, R as isFilter, Q as isGenerator, p as isReview } from '../classroomDB-BgfrVb8d.js';
|
|
3
|
+
export { D as DataLayerProvider } from '../dataLayerProvider-CZxC9GtB.js';
|
|
4
4
|
import { C as CardHistory, c as CardRecord, i as QuestionRecord } from '../types-legacy-6ettoclI.js';
|
|
5
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, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from '../types-legacy-6ettoclI.js';
|
|
6
6
|
import { DataShape, ParsedCard } from '@vue-skuilder/common';
|
|
@@ -12,6 +12,163 @@ declare abstract class Loggable {
|
|
|
12
12
|
protected error(...args: unknown[]): void;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Shared context available to all filters in a pipeline.
|
|
17
|
+
*
|
|
18
|
+
* Built once per getWeightedCards() call and passed to each filter.
|
|
19
|
+
* This avoids repeated lookups for common data like user ELO.
|
|
20
|
+
*/
|
|
21
|
+
interface FilterContext {
|
|
22
|
+
/** User database interface */
|
|
23
|
+
user: UserDBInterface;
|
|
24
|
+
/** Course database interface */
|
|
25
|
+
course: CourseDBInterface;
|
|
26
|
+
/** User's global ELO score for this course */
|
|
27
|
+
userElo: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A filter that transforms a list of weighted cards.
|
|
31
|
+
*
|
|
32
|
+
* Filters are pure transforms - they receive cards and context,
|
|
33
|
+
* and return a modified list of cards. No delegate wrapping,
|
|
34
|
+
* no side effects beyond provenance tracking.
|
|
35
|
+
*
|
|
36
|
+
* ## Implementation Guidelines
|
|
37
|
+
*
|
|
38
|
+
* 1. **Append provenance**: Every filter should add a StrategyContribution
|
|
39
|
+
* entry documenting its decision for each card.
|
|
40
|
+
*
|
|
41
|
+
* 2. **Use multipliers**: Adjust scores by multiplying, not replacing.
|
|
42
|
+
* This ensures filter order doesn't matter.
|
|
43
|
+
*
|
|
44
|
+
* 3. **Score 0 for exclusion**: To exclude a card, set score to 0.
|
|
45
|
+
* Don't filter it out - let provenance show why it was excluded.
|
|
46
|
+
*
|
|
47
|
+
* 4. **Don't sort**: The Pipeline handles final sorting.
|
|
48
|
+
* Filters just transform scores.
|
|
49
|
+
*
|
|
50
|
+
* ## Example Implementation
|
|
51
|
+
*
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const myFilter: CardFilter = {
|
|
54
|
+
* name: 'My Filter',
|
|
55
|
+
* async transform(cards, context) {
|
|
56
|
+
* return cards.map(card => {
|
|
57
|
+
* const multiplier = computeMultiplier(card, context);
|
|
58
|
+
* const newScore = card.score * multiplier;
|
|
59
|
+
* return {
|
|
60
|
+
* ...card,
|
|
61
|
+
* score: newScore,
|
|
62
|
+
* provenance: [...card.provenance, {
|
|
63
|
+
* strategy: 'myFilter',
|
|
64
|
+
* strategyName: 'My Filter',
|
|
65
|
+
* strategyId: 'MY_FILTER',
|
|
66
|
+
* action: multiplier < 1 ? 'penalized' : 'passed',
|
|
67
|
+
* score: newScore,
|
|
68
|
+
* reason: 'Explanation of decision'
|
|
69
|
+
* }]
|
|
70
|
+
* };
|
|
71
|
+
* });
|
|
72
|
+
* }
|
|
73
|
+
* };
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
interface CardFilter {
|
|
77
|
+
/** Human-readable name for this filter */
|
|
78
|
+
name: string;
|
|
79
|
+
/**
|
|
80
|
+
* Transform a list of weighted cards.
|
|
81
|
+
*
|
|
82
|
+
* @param cards - Cards to transform (already scored by generator)
|
|
83
|
+
* @param context - Shared context (user, course, userElo, etc.)
|
|
84
|
+
* @returns Transformed cards with updated scores and provenance
|
|
85
|
+
*/
|
|
86
|
+
transform(cards: WeightedCard[], context: FilterContext): Promise<WeightedCard[]>;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Factory function type for creating filters from configuration.
|
|
90
|
+
*
|
|
91
|
+
* Used by PipelineAssembler to instantiate filters from strategy documents.
|
|
92
|
+
*/
|
|
93
|
+
type CardFilterFactory<TConfig = unknown> = (config: TConfig) => CardFilter;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Context available to generators when producing candidates.
|
|
97
|
+
*
|
|
98
|
+
* Built once per getWeightedCards() call by the Pipeline.
|
|
99
|
+
*/
|
|
100
|
+
interface GeneratorContext {
|
|
101
|
+
/** User database interface */
|
|
102
|
+
user: UserDBInterface;
|
|
103
|
+
/** Course database interface */
|
|
104
|
+
course: CourseDBInterface;
|
|
105
|
+
/** User's global ELO score for this course */
|
|
106
|
+
userElo: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A generator that produces candidate cards with initial scores.
|
|
110
|
+
*
|
|
111
|
+
* Generators are the "source" stage of a navigation pipeline.
|
|
112
|
+
* They query the database for eligible cards and assign initial
|
|
113
|
+
* suitability scores based on their strategy (ELO proximity,
|
|
114
|
+
* review urgency, fixed order, etc.).
|
|
115
|
+
*
|
|
116
|
+
* ## Implementation Guidelines
|
|
117
|
+
*
|
|
118
|
+
* 1. **Create provenance**: Each card should have a provenance entry
|
|
119
|
+
* with action='generated' documenting why it was selected.
|
|
120
|
+
*
|
|
121
|
+
* 2. **Score semantics**: Higher scores = more suitable for presentation.
|
|
122
|
+
* Scores should be in [0, 1] range for composability.
|
|
123
|
+
*
|
|
124
|
+
* 3. **Limit handling**: Respect the limit parameter, but may over-fetch
|
|
125
|
+
* internally if needed for scoring accuracy.
|
|
126
|
+
*
|
|
127
|
+
* 4. **Sort before returning**: Return cards sorted by score descending.
|
|
128
|
+
*
|
|
129
|
+
* ## Example Implementation
|
|
130
|
+
*
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const myGenerator: CardGenerator = {
|
|
133
|
+
* name: 'My Generator',
|
|
134
|
+
* async getWeightedCards(limit, context) {
|
|
135
|
+
* const candidates = await fetchCandidates(context.course, limit);
|
|
136
|
+
* return candidates.map(c => ({
|
|
137
|
+
* cardId: c.id,
|
|
138
|
+
* courseId: context.course.getCourseID(),
|
|
139
|
+
* score: computeScore(c, context),
|
|
140
|
+
* provenance: [{
|
|
141
|
+
* strategy: 'myGenerator',
|
|
142
|
+
* strategyName: 'My Generator',
|
|
143
|
+
* strategyId: 'MY_GENERATOR',
|
|
144
|
+
* action: 'generated',
|
|
145
|
+
* score: computeScore(c, context),
|
|
146
|
+
* reason: 'Explanation of selection'
|
|
147
|
+
* }]
|
|
148
|
+
* }));
|
|
149
|
+
* }
|
|
150
|
+
* };
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
interface CardGenerator {
|
|
154
|
+
/** Human-readable name for this generator */
|
|
155
|
+
name: string;
|
|
156
|
+
/**
|
|
157
|
+
* Produce candidate cards with initial scores.
|
|
158
|
+
*
|
|
159
|
+
* @param limit - Maximum number of cards to return
|
|
160
|
+
* @param context - Shared context (user, course, userElo, etc.)
|
|
161
|
+
* @returns Cards sorted by score descending, with provenance
|
|
162
|
+
*/
|
|
163
|
+
getWeightedCards(limit: number, context: GeneratorContext): Promise<WeightedCard[]>;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Factory function type for creating generators from configuration.
|
|
167
|
+
*
|
|
168
|
+
* Used by PipelineAssembler to instantiate generators from strategy documents.
|
|
169
|
+
*/
|
|
170
|
+
type CardGeneratorFactory<TConfig = unknown> = (config: TConfig) => CardGenerator;
|
|
171
|
+
|
|
15
172
|
declare function areQuestionRecords(h: CardHistory<CardRecord>): h is CardHistory<QuestionRecord>;
|
|
16
173
|
declare function isQuestionRecord(c: CardRecord): c is QuestionRecord;
|
|
17
174
|
declare function getCardHistoryID(courseID: string, cardID: string): PouchDB.Core.DocumentId;
|
|
@@ -25,25 +182,6 @@ interface PouchDBError extends Error {
|
|
|
25
182
|
}
|
|
26
183
|
declare function docIsDeleted(e: PouchDBError): boolean;
|
|
27
184
|
|
|
28
|
-
declare enum Navigators {
|
|
29
|
-
ELO = "elo",
|
|
30
|
-
HARDCODED = "hardcodedOrder"
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* A content-navigator provides runtime steering of study sessions.
|
|
34
|
-
*/
|
|
35
|
-
declare abstract class ContentNavigator implements StudyContentSource {
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
38
|
-
* @param user
|
|
39
|
-
* @param strategyData
|
|
40
|
-
* @returns the runtime object used to steer a study session.
|
|
41
|
-
*/
|
|
42
|
-
static create(user: UserDBInterface, course: CourseDBInterface, strategyData: ContentNavigationStrategyData): Promise<ContentNavigator>;
|
|
43
|
-
abstract getPendingReviews(): Promise<(StudySessionReviewItem & ScheduledCard)[]>;
|
|
44
|
-
abstract getNewCards(n?: number): Promise<StudySessionNewItem[]>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
185
|
/**
|
|
48
186
|
* Interface representing the result of a bulk import operation for a single card
|
|
49
187
|
*/
|
|
@@ -89,4 +227,4 @@ declare function validateProcessorConfig(config: Partial<BulkCardProcessorConfig
|
|
|
89
227
|
errorMessage?: string;
|
|
90
228
|
};
|
|
91
229
|
|
|
92
|
-
export { type BulkCardProcessorConfig,
|
|
230
|
+
export { type BulkCardProcessorConfig, type CardFilter, type CardFilterFactory, type CardGenerator, type CardGeneratorFactory, CardHistory, CardRecord, CourseDBInterface, type FilterContext, type GeneratorContext, type ImportResult, Loggable, QuestionRecord, UserDBInterface, WeightedCard, areQuestionRecords, docIsDeleted, getCardHistoryID, importParsedCards, isQuestionRecord, parseCardHistoryID, validateProcessorConfig };
|