@vue-skuilder/db 0.2.15 → 0.2.17
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/core/index.d.cts +48 -1
- package/dist/core/index.d.ts +48 -1
- package/dist/core/index.js +112 -6
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +109 -6
- package/dist/core/index.mjs.map +1 -1
- package/dist/impl/couch/index.js +106 -6
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +106 -6
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.js +106 -6
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +106 -6
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +175 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +172 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/core/navigators/StrategyPressureDebugger.ts +76 -0
- package/src/core/navigators/generators/prescribed.ts +122 -7
- package/src/core/navigators/index.ts +12 -0
- package/src/study/SessionController.ts +7 -1
- package/src/study/SessionDebugger.ts +2 -0
- package/src/study/SessionOverlay.ts +113 -0
- package/src/study/services/CardHydrationService.ts +9 -1
package/dist/index.d.cts
CHANGED
|
@@ -3,8 +3,8 @@ export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as Ass
|
|
|
3
3
|
import { D as DataLayerProvider } from './dataLayerProvider-CpwpT1rM.cjs';
|
|
4
4
|
import { C as CardHistory, c as CardRecord, d as QuestionRecord } from './types-legacy-4tlwHnXo.cjs';
|
|
5
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
|
-
import { SrsBacklogDebug, Loggable } from './core/index.cjs';
|
|
7
|
-
export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, DiversityRerankOptions, FilterContext, FilterImpact, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineForecaster, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, clearSrsBacklogDebug, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getActivePipeline, getCardHistoryID, getDefaultLearnableWeight, getSrsBacklogDebug, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig } from './core/index.cjs';
|
|
6
|
+
import { SrsBacklogDebug, StrategyPressureDebug, Loggable } from './core/index.cjs';
|
|
7
|
+
export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, DiversityRerankOptions, FilterContext, FilterImpact, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineForecaster, PipelineRunReport, PressureGaugeDebug, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, captureStrategyPressure, clearSrsBacklogDebug, clearStrategyPressureDebug, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getActivePipeline, getCardHistoryID, getDefaultLearnableWeight, getSrsBacklogDebug, getStrategyPressureDebug, 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
9
|
import { S as StaticCourseManifest } from './types-BFUa1pa3.cjs';
|
|
10
10
|
export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-BFUa1pa3.cjs';
|
|
@@ -365,6 +365,8 @@ interface SessionDebugSnapshot {
|
|
|
365
365
|
failedQ: SessionQueueDebug;
|
|
366
366
|
/** SRS backlog state per course (drives the "is review starvation permanent?" read). */
|
|
367
367
|
reviewBacklog: SrsBacklogDebug[];
|
|
368
|
+
/** Per-strategy backpressure gauges (prescribed pressure, practice debt, ...). */
|
|
369
|
+
strategyPressure: StrategyPressureDebug[];
|
|
368
370
|
/** Every card the learner has interacted with this session, draw order. */
|
|
369
371
|
drawnCards: SessionDrawnCardDebug[];
|
|
370
372
|
}
|
|
@@ -1521,4 +1523,4 @@ interface CouchDbUserDoc extends PouchDB.Authentication.User {
|
|
|
1521
1523
|
entitlements: UserEntitlements;
|
|
1522
1524
|
}
|
|
1523
1525
|
|
|
1524
|
-
export { type ActiveSessionHandle, 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, REVIEW_TIME_FORMAT, ReplanHints, type ReplanOptions, type ResponseResult, type RestoreProgress, type SessionAction, SessionController, type SessionControls, type SessionDebugSnapshot, type SessionDebugTarget, type SessionDrawnCardDebug, type SessionOutcome, type SessionQueueDebug, type SessionQueueItemDebug, type SessionRunReport, type SourceBatch, type SourceMixer, type SourceSelectionBreakdown, type SourceSummary, SrsBacklogDebug, StaticCourseManifest, type StaticCourseValidation, StaticToCouchDBMigrator, StudyContentSource, StudySessionItem, type StudySessionRecord, TagFilteredContentSource, type UserAccountStatus, UserDBInterface, type UserEntitlements, type ValidationIssue, type ValidationResult, WeightedCard, _resetDataLayer, captureMixerRun, clearStaleSessionDebugState, endSessionTracking, ensureAppDataDirectory, getActiveController, getAppDataDirectory, getDataLayer, getDbPath, initializeDataDirectory, initializeDataLayer, isDataShapeRegistered, isDataShapeSchemaAvailable, isQuestionTypeRegistered, makeScheduledCardId, mixerDebugAPI, mountMixerDebugger, mountSessionDebugger, processCustomQuestionsData, recordCardPresentation, registerActiveController, registerBlanksCard, registerCustomQuestionTypes, registerDataShape, registerQuestionType, registerSeedData, removeCustomQuestionTypes, removeDataShape, removeQuestionType, sessionDebugAPI, snapshotQueues, startSessionTracking, toggleSessionOverlay, validateMigration, validateStaticCourse };
|
|
1526
|
+
export { type ActiveSessionHandle, 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, REVIEW_TIME_FORMAT, ReplanHints, type ReplanOptions, type ResponseResult, type RestoreProgress, type SessionAction, SessionController, type SessionControls, type SessionDebugSnapshot, type SessionDebugTarget, type SessionDrawnCardDebug, type SessionOutcome, type SessionQueueDebug, type SessionQueueItemDebug, type SessionRunReport, type SourceBatch, type SourceMixer, type SourceSelectionBreakdown, type SourceSummary, SrsBacklogDebug, StaticCourseManifest, type StaticCourseValidation, StaticToCouchDBMigrator, StrategyPressureDebug, StudyContentSource, StudySessionItem, type StudySessionRecord, TagFilteredContentSource, type UserAccountStatus, UserDBInterface, type UserEntitlements, type ValidationIssue, type ValidationResult, WeightedCard, _resetDataLayer, captureMixerRun, clearStaleSessionDebugState, endSessionTracking, ensureAppDataDirectory, getActiveController, getAppDataDirectory, getDataLayer, getDbPath, initializeDataDirectory, initializeDataLayer, isDataShapeRegistered, isDataShapeSchemaAvailable, isQuestionTypeRegistered, makeScheduledCardId, mixerDebugAPI, mountMixerDebugger, mountSessionDebugger, processCustomQuestionsData, recordCardPresentation, registerActiveController, registerBlanksCard, registerCustomQuestionTypes, registerDataShape, registerQuestionType, registerSeedData, removeCustomQuestionTypes, removeDataShape, removeQuestionType, sessionDebugAPI, snapshotQueues, startSessionTracking, toggleSessionOverlay, validateMigration, validateStaticCourse };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as Ass
|
|
|
3
3
|
import { D as DataLayerProvider } from './dataLayerProvider-BWayUIoK.js';
|
|
4
4
|
import { C as CardHistory, c as CardRecord, d as QuestionRecord } from './types-legacy-4tlwHnXo.js';
|
|
5
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
|
-
import { SrsBacklogDebug, Loggable } from './core/index.js';
|
|
7
|
-
export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, DiversityRerankOptions, FilterContext, FilterImpact, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineForecaster, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, clearSrsBacklogDebug, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getActivePipeline, getCardHistoryID, getDefaultLearnableWeight, getSrsBacklogDebug, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig } from './core/index.js';
|
|
6
|
+
import { SrsBacklogDebug, StrategyPressureDebug, Loggable } from './core/index.js';
|
|
7
|
+
export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, DIVERSITY_FLOOR, DIVERSITY_STRENGTH, DiversityRerankOptions, FilterContext, FilterImpact, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineForecaster, PipelineRunReport, PressureGaugeDebug, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, captureStrategyPressure, clearSrsBacklogDebug, clearStrategyPressureDebug, computeOutcomeSignal, computeStrategyGradient, diversityRerank, docIsDeleted, getActivePipeline, getCardHistoryID, getDefaultLearnableWeight, getSrsBacklogDebug, getStrategyPressureDebug, 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
9
|
import { S as StaticCourseManifest } from './types-CHgpWQAY.js';
|
|
10
10
|
export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-CHgpWQAY.js';
|
|
@@ -365,6 +365,8 @@ interface SessionDebugSnapshot {
|
|
|
365
365
|
failedQ: SessionQueueDebug;
|
|
366
366
|
/** SRS backlog state per course (drives the "is review starvation permanent?" read). */
|
|
367
367
|
reviewBacklog: SrsBacklogDebug[];
|
|
368
|
+
/** Per-strategy backpressure gauges (prescribed pressure, practice debt, ...). */
|
|
369
|
+
strategyPressure: StrategyPressureDebug[];
|
|
368
370
|
/** Every card the learner has interacted with this session, draw order. */
|
|
369
371
|
drawnCards: SessionDrawnCardDebug[];
|
|
370
372
|
}
|
|
@@ -1521,4 +1523,4 @@ interface CouchDbUserDoc extends PouchDB.Authentication.User {
|
|
|
1521
1523
|
entitlements: UserEntitlements;
|
|
1522
1524
|
}
|
|
1523
1525
|
|
|
1524
|
-
export { type ActiveSessionHandle, 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, REVIEW_TIME_FORMAT, ReplanHints, type ReplanOptions, type ResponseResult, type RestoreProgress, type SessionAction, SessionController, type SessionControls, type SessionDebugSnapshot, type SessionDebugTarget, type SessionDrawnCardDebug, type SessionOutcome, type SessionQueueDebug, type SessionQueueItemDebug, type SessionRunReport, type SourceBatch, type SourceMixer, type SourceSelectionBreakdown, type SourceSummary, SrsBacklogDebug, StaticCourseManifest, type StaticCourseValidation, StaticToCouchDBMigrator, StudyContentSource, StudySessionItem, type StudySessionRecord, TagFilteredContentSource, type UserAccountStatus, UserDBInterface, type UserEntitlements, type ValidationIssue, type ValidationResult, WeightedCard, _resetDataLayer, captureMixerRun, clearStaleSessionDebugState, endSessionTracking, ensureAppDataDirectory, getActiveController, getAppDataDirectory, getDataLayer, getDbPath, initializeDataDirectory, initializeDataLayer, isDataShapeRegistered, isDataShapeSchemaAvailable, isQuestionTypeRegistered, makeScheduledCardId, mixerDebugAPI, mountMixerDebugger, mountSessionDebugger, processCustomQuestionsData, recordCardPresentation, registerActiveController, registerBlanksCard, registerCustomQuestionTypes, registerDataShape, registerQuestionType, registerSeedData, removeCustomQuestionTypes, removeDataShape, removeQuestionType, sessionDebugAPI, snapshotQueues, startSessionTracking, toggleSessionOverlay, validateMigration, validateStaticCourse };
|
|
1526
|
+
export { type ActiveSessionHandle, 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, REVIEW_TIME_FORMAT, ReplanHints, type ReplanOptions, type ResponseResult, type RestoreProgress, type SessionAction, SessionController, type SessionControls, type SessionDebugSnapshot, type SessionDebugTarget, type SessionDrawnCardDebug, type SessionOutcome, type SessionQueueDebug, type SessionQueueItemDebug, type SessionRunReport, type SourceBatch, type SourceMixer, type SourceSelectionBreakdown, type SourceSummary, SrsBacklogDebug, StaticCourseManifest, type StaticCourseValidation, StaticToCouchDBMigrator, StrategyPressureDebug, StudyContentSource, StudySessionItem, type StudySessionRecord, TagFilteredContentSource, type UserAccountStatus, UserDBInterface, type UserEntitlements, type ValidationIssue, type ValidationResult, WeightedCard, _resetDataLayer, captureMixerRun, clearStaleSessionDebugState, endSessionTracking, ensureAppDataDirectory, getActiveController, getAppDataDirectory, getDataLayer, getDbPath, initializeDataDirectory, initializeDataLayer, isDataShapeRegistered, isDataShapeSchemaAvailable, isQuestionTypeRegistered, makeScheduledCardId, mixerDebugAPI, mountMixerDebugger, mountSessionDebugger, processCustomQuestionsData, recordCardPresentation, registerActiveController, registerBlanksCard, registerCustomQuestionTypes, registerDataShape, registerQuestionType, registerSeedData, removeCustomQuestionTypes, removeDataShape, removeQuestionType, sessionDebugAPI, snapshotQueues, startSessionTracking, toggleSessionOverlay, validateMigration, validateStaticCourse };
|
package/dist/index.js
CHANGED
|
@@ -1820,6 +1820,30 @@ var init_SrsDebugger = __esm({
|
|
|
1820
1820
|
}
|
|
1821
1821
|
});
|
|
1822
1822
|
|
|
1823
|
+
// src/core/navigators/StrategyPressureDebugger.ts
|
|
1824
|
+
var StrategyPressureDebugger_exports = {};
|
|
1825
|
+
__export(StrategyPressureDebugger_exports, {
|
|
1826
|
+
captureStrategyPressure: () => captureStrategyPressure,
|
|
1827
|
+
clearStrategyPressureDebug: () => clearStrategyPressureDebug,
|
|
1828
|
+
getStrategyPressureDebug: () => getStrategyPressureDebug
|
|
1829
|
+
});
|
|
1830
|
+
function captureStrategyPressure(snapshot) {
|
|
1831
|
+
snapshots2.set(`${snapshot.source}:${snapshot.courseId}`, snapshot);
|
|
1832
|
+
}
|
|
1833
|
+
function getStrategyPressureDebug() {
|
|
1834
|
+
return [...snapshots2.values()].sort((a, b) => b.timestamp - a.timestamp);
|
|
1835
|
+
}
|
|
1836
|
+
function clearStrategyPressureDebug() {
|
|
1837
|
+
snapshots2.clear();
|
|
1838
|
+
}
|
|
1839
|
+
var snapshots2;
|
|
1840
|
+
var init_StrategyPressureDebugger = __esm({
|
|
1841
|
+
"src/core/navigators/StrategyPressureDebugger.ts"() {
|
|
1842
|
+
"use strict";
|
|
1843
|
+
snapshots2 = /* @__PURE__ */ new Map();
|
|
1844
|
+
}
|
|
1845
|
+
});
|
|
1846
|
+
|
|
1823
1847
|
// src/core/navigators/generators/CompositeGenerator.ts
|
|
1824
1848
|
var CompositeGenerator_exports = {};
|
|
1825
1849
|
__export(CompositeGenerator_exports, {
|
|
@@ -2184,6 +2208,13 @@ function shuffleInPlace(arr) {
|
|
|
2184
2208
|
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
2185
2209
|
}
|
|
2186
2210
|
}
|
|
2211
|
+
function formatAge(ms) {
|
|
2212
|
+
const minutes = Math.max(0, Math.round(ms / 6e4));
|
|
2213
|
+
if (minutes < 60) return `${minutes}m`;
|
|
2214
|
+
const hours = Math.round(minutes / 60);
|
|
2215
|
+
if (hours < 24) return `${hours}h`;
|
|
2216
|
+
return `${Math.round(hours / 24)}d`;
|
|
2217
|
+
}
|
|
2187
2218
|
function pickTopByScore(cards, limit) {
|
|
2188
2219
|
return [...cards].sort((a, b) => b.score - a.score || a.cardId.localeCompare(b.cardId)).slice(0, limit);
|
|
2189
2220
|
}
|
|
@@ -2192,6 +2223,7 @@ var init_prescribed = __esm({
|
|
|
2192
2223
|
"src/core/navigators/generators/prescribed.ts"() {
|
|
2193
2224
|
"use strict";
|
|
2194
2225
|
init_navigators();
|
|
2226
|
+
init_StrategyPressureDebugger();
|
|
2195
2227
|
init_logger();
|
|
2196
2228
|
DEFAULT_FRESHNESS_WINDOW = 3;
|
|
2197
2229
|
DEFAULT_MAX_DIRECT_PER_RUN = 3;
|
|
@@ -2268,6 +2300,7 @@ var init_prescribed = __esm({
|
|
|
2268
2300
|
const groupRuntimes = [];
|
|
2269
2301
|
const priorPracticeDebt = progress.practiceDebt ?? {};
|
|
2270
2302
|
const nextPracticeDebt = {};
|
|
2303
|
+
const practiceDebtsByGroup = /* @__PURE__ */ new Map();
|
|
2271
2304
|
for (const group of this.config.groups) {
|
|
2272
2305
|
const runtime = this.buildGroupRuntimeState({
|
|
2273
2306
|
group,
|
|
@@ -2316,7 +2349,7 @@ var init_prescribed = __esm({
|
|
|
2316
2349
|
courseId,
|
|
2317
2350
|
emittedIds
|
|
2318
2351
|
);
|
|
2319
|
-
const
|
|
2352
|
+
const practice = this.buildPracticeCards({
|
|
2320
2353
|
group,
|
|
2321
2354
|
courseId,
|
|
2322
2355
|
emittedIds,
|
|
@@ -2329,7 +2362,8 @@ var init_prescribed = __esm({
|
|
|
2329
2362
|
priorPracticeDebt,
|
|
2330
2363
|
nextPracticeDebt
|
|
2331
2364
|
});
|
|
2332
|
-
|
|
2365
|
+
practiceDebtsByGroup.set(group.id, practice.debts);
|
|
2366
|
+
emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practice.cards);
|
|
2333
2367
|
}
|
|
2334
2368
|
nextState.practiceDebt = nextPracticeDebt;
|
|
2335
2369
|
const hintSummary = this.buildSupportHintSummary(groupRuntimes);
|
|
@@ -2345,6 +2379,7 @@ var init_prescribed = __esm({
|
|
|
2345
2379
|
} else {
|
|
2346
2380
|
logger.info("[Prescribed] No hints to emit (no blocked targets or no support tags)");
|
|
2347
2381
|
}
|
|
2382
|
+
this.capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints);
|
|
2348
2383
|
if (emitted.length === 0) {
|
|
2349
2384
|
logger.info(
|
|
2350
2385
|
"[Prescribed] 0 cards emitted (all targets blocked, authored/discovered support candidates exhausted)" + (hints ? " \u2014 boost hints emitted but may not survive filters" : "")
|
|
@@ -2406,6 +2441,60 @@ var init_prescribed = __esm({
|
|
|
2406
2441
|
supportTags: [...supportTags].sort()
|
|
2407
2442
|
};
|
|
2408
2443
|
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Translate this run's per-group runtimes and practice debts into gauges on
|
|
2446
|
+
* the generic strategy-pressure debug channel (rendered by the live session
|
|
2447
|
+
* overlay's "strategy backpressure" section).
|
|
2448
|
+
*/
|
|
2449
|
+
capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints) {
|
|
2450
|
+
const now = Date.now();
|
|
2451
|
+
const gauges = [];
|
|
2452
|
+
for (const runtime of groupRuntimes) {
|
|
2453
|
+
const group = runtime.group;
|
|
2454
|
+
const window2 = group.freshnessWindowSessions ?? DEFAULT_FRESHNESS_WINDOW;
|
|
2455
|
+
gauges.push({
|
|
2456
|
+
id: `group:${group.id}:target`,
|
|
2457
|
+
label: `${group.id} targets`,
|
|
2458
|
+
multiplier: runtime.pressureMultiplier,
|
|
2459
|
+
max: MAX_TARGET_MULTIPLIER,
|
|
2460
|
+
detail: `${runtime.pendingTargets.length} pending (${runtime.surfaceableTargets.length} surfaceable, ${runtime.blockedTargets.length} blocked) \xB7 sinceSurfaced ${runtime.sessionsSinceSurfaced}/${window2}`,
|
|
2461
|
+
items: runtime.blockedTargets.map((cardId) => ({ label: cardId, value: "blocked" }))
|
|
2462
|
+
});
|
|
2463
|
+
if (runtime.blockedTargets.length > 0) {
|
|
2464
|
+
const mode = runtime.supportCandidates.length > 0 ? "direct-support" : runtime.discoveredSupportCandidates.length > 0 ? "inserted-support" : "boost-only";
|
|
2465
|
+
gauges.push({
|
|
2466
|
+
id: `group:${group.id}:support`,
|
|
2467
|
+
label: `${group.id} support`,
|
|
2468
|
+
multiplier: runtime.supportMultiplier,
|
|
2469
|
+
max: MAX_SUPPORT_MULTIPLIER,
|
|
2470
|
+
detail: `mode=${mode} \xB7 ${runtime.supportTags.length} support tag(s)`,
|
|
2471
|
+
items: runtime.supportTags.map((tag) => ({ label: tag }))
|
|
2472
|
+
});
|
|
2473
|
+
}
|
|
2474
|
+
const debts = practiceDebtsByGroup.get(group.id) ?? [];
|
|
2475
|
+
if (debts.length > 0) {
|
|
2476
|
+
gauges.push({
|
|
2477
|
+
id: `group:${group.id}:practice-debt`,
|
|
2478
|
+
label: `${group.id} practice debt`,
|
|
2479
|
+
multiplier: Math.max(...debts.map((d) => d.multiplier)),
|
|
2480
|
+
max: MAX_PRACTICE_MULTIPLIER,
|
|
2481
|
+
detail: `${debts.length} under-practiced skill(s)`,
|
|
2482
|
+
items: debts.map((d) => ({
|
|
2483
|
+
label: d.tag,
|
|
2484
|
+
value: `\xD7${d.multiplier.toFixed(2)} \xB7 open ${formatAge(now - new Date(d.firstOwedAt).getTime())}`
|
|
2485
|
+
}))
|
|
2486
|
+
});
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
captureStrategyPressure({
|
|
2490
|
+
source: "prescribed",
|
|
2491
|
+
courseId,
|
|
2492
|
+
gauges,
|
|
2493
|
+
topScore: emitted.length > 0 ? Math.max(...emitted.map((c) => c.score)) : null,
|
|
2494
|
+
hintsLabel: hints?._label,
|
|
2495
|
+
timestamp: now
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2409
2498
|
parseConfig(serializedData) {
|
|
2410
2499
|
try {
|
|
2411
2500
|
const parsed = JSON.parse(serializedData);
|
|
@@ -2562,6 +2651,7 @@ var init_prescribed = __esm({
|
|
|
2562
2651
|
supportTags: [...supportTags],
|
|
2563
2652
|
pressureMultiplier,
|
|
2564
2653
|
supportMultiplier,
|
|
2654
|
+
sessionsSinceSurfaced,
|
|
2565
2655
|
debugVersion: PRESCRIBED_DEBUG_VERSION
|
|
2566
2656
|
};
|
|
2567
2657
|
}
|
|
@@ -2694,13 +2784,13 @@ var init_prescribed = __esm({
|
|
|
2694
2784
|
nextPracticeDebt
|
|
2695
2785
|
} = args;
|
|
2696
2786
|
const patterns = group.practiceTagPatterns ?? [];
|
|
2697
|
-
if (patterns.length === 0) return [];
|
|
2787
|
+
if (patterns.length === 0) return { cards: [], debts: [] };
|
|
2698
2788
|
const practiceMinCount = group.practiceMinCount ?? DEFAULT_PRACTICE_MIN_COUNT;
|
|
2699
2789
|
const maxPractice = group.maxPracticeCardsPerRun ?? DEFAULT_MAX_PRACTICE_PER_RUN;
|
|
2700
2790
|
const practiceTags = [...cardsByTag.keys()].filter(
|
|
2701
2791
|
(tag) => patterns.some((p) => matchesTagPattern(tag, p)) && this.isUnlockedGatedSkill(tag, hierarchyConfigs, userTagElo, userGlobalElo) && (userTagElo[tag]?.count ?? 0) < practiceMinCount
|
|
2702
2792
|
);
|
|
2703
|
-
if (practiceTags.length === 0) return [];
|
|
2793
|
+
if (practiceTags.length === 0) return { cards: [], debts: [] };
|
|
2704
2794
|
const now = Date.now();
|
|
2705
2795
|
const DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2706
2796
|
const tagMultiplier = /* @__PURE__ */ new Map();
|
|
@@ -2715,6 +2805,11 @@ var init_prescribed = __esm({
|
|
|
2715
2805
|
);
|
|
2716
2806
|
tagMultiplier.set(tag, mult);
|
|
2717
2807
|
}
|
|
2808
|
+
const debts = practiceTags.map((tag) => ({
|
|
2809
|
+
tag,
|
|
2810
|
+
multiplier: tagMultiplier.get(tag) ?? PRACTICE_BASE_MULT,
|
|
2811
|
+
firstOwedAt: nextPracticeDebt[tag]
|
|
2812
|
+
})).sort((a, b) => b.multiplier - a.multiplier || a.tag.localeCompare(b.tag));
|
|
2718
2813
|
const practiceCardIds = this.findDiscoveredSupportCards({
|
|
2719
2814
|
supportTags: practiceTags,
|
|
2720
2815
|
cardsByTag,
|
|
@@ -2723,7 +2818,7 @@ var init_prescribed = __esm({
|
|
|
2723
2818
|
excludedIds: emittedIds,
|
|
2724
2819
|
limit: maxPractice
|
|
2725
2820
|
});
|
|
2726
|
-
if (practiceCardIds.length === 0) return [];
|
|
2821
|
+
if (practiceCardIds.length === 0) return { cards: [], debts };
|
|
2727
2822
|
logger.info(
|
|
2728
2823
|
`[Prescribed] Group '${group.id}' practice: ${practiceTags.length} unlocked under-practiced skill(s), emitting ${practiceCardIds.length} drill card(s)`
|
|
2729
2824
|
);
|
|
@@ -2753,7 +2848,7 @@ var init_prescribed = __esm({
|
|
|
2753
2848
|
]
|
|
2754
2849
|
});
|
|
2755
2850
|
}
|
|
2756
|
-
return cards;
|
|
2851
|
+
return { cards, debts };
|
|
2757
2852
|
}
|
|
2758
2853
|
/**
|
|
2759
2854
|
* True for a skill that was *gated and is now reached*: it has at least one
|
|
@@ -5430,6 +5525,7 @@ var init_3 = __esm({
|
|
|
5430
5525
|
"./PipelineAssembler.ts": () => Promise.resolve().then(() => (init_PipelineAssembler(), PipelineAssembler_exports)),
|
|
5431
5526
|
"./PipelineDebugger.ts": () => Promise.resolve().then(() => (init_PipelineDebugger(), PipelineDebugger_exports)),
|
|
5432
5527
|
"./SrsDebugger.ts": () => Promise.resolve().then(() => (init_SrsDebugger(), SrsDebugger_exports)),
|
|
5528
|
+
"./StrategyPressureDebugger.ts": () => Promise.resolve().then(() => (init_StrategyPressureDebugger(), StrategyPressureDebugger_exports)),
|
|
5433
5529
|
"./defaults.ts": () => Promise.resolve().then(() => (init_defaults(), defaults_exports)),
|
|
5434
5530
|
"./diversityRerank.ts": () => Promise.resolve().then(() => (init_diversityRerank(), diversityRerank_exports)),
|
|
5435
5531
|
"./filters/WeightedFilter.ts": () => Promise.resolve().then(() => (init_WeightedFilter(), WeightedFilter_exports)),
|
|
@@ -5462,7 +5558,9 @@ __export(navigators_exports, {
|
|
|
5462
5558
|
NavigatorRole: () => NavigatorRole,
|
|
5463
5559
|
NavigatorRoles: () => NavigatorRoles,
|
|
5464
5560
|
Navigators: () => Navigators,
|
|
5561
|
+
captureStrategyPressure: () => captureStrategyPressure,
|
|
5465
5562
|
clearSrsBacklogDebug: () => clearSrsBacklogDebug,
|
|
5563
|
+
clearStrategyPressureDebug: () => clearStrategyPressureDebug,
|
|
5466
5564
|
diversityRerank: () => diversityRerank,
|
|
5467
5565
|
getActivePipeline: () => getActivePipeline,
|
|
5468
5566
|
getCardOrigin: () => getCardOrigin,
|
|
@@ -5470,6 +5568,7 @@ __export(navigators_exports, {
|
|
|
5470
5568
|
getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
|
|
5471
5569
|
getRegisteredNavigatorRole: () => getRegisteredNavigatorRole,
|
|
5472
5570
|
getSrsBacklogDebug: () => getSrsBacklogDebug,
|
|
5571
|
+
getStrategyPressureDebug: () => getStrategyPressureDebug,
|
|
5473
5572
|
hasRegisteredNavigator: () => hasRegisteredNavigator,
|
|
5474
5573
|
initializeNavigatorRegistry: () => initializeNavigatorRegistry,
|
|
5475
5574
|
isFilter: () => isFilter,
|
|
@@ -5552,6 +5651,7 @@ var init_navigators = __esm({
|
|
|
5552
5651
|
init_diversityRerank();
|
|
5553
5652
|
init_PipelineDebugger();
|
|
5554
5653
|
init_SrsDebugger();
|
|
5654
|
+
init_StrategyPressureDebugger();
|
|
5555
5655
|
init_logger();
|
|
5556
5656
|
init_();
|
|
5557
5657
|
init_2();
|
|
@@ -10589,8 +10689,10 @@ __export(index_exports, {
|
|
|
10589
10689
|
areQuestionRecords: () => areQuestionRecords,
|
|
10590
10690
|
buildStrategyStateId: () => buildStrategyStateId,
|
|
10591
10691
|
captureMixerRun: () => captureMixerRun,
|
|
10692
|
+
captureStrategyPressure: () => captureStrategyPressure,
|
|
10592
10693
|
clearSrsBacklogDebug: () => clearSrsBacklogDebug,
|
|
10593
10694
|
clearStaleSessionDebugState: () => clearStaleSessionDebugState,
|
|
10695
|
+
clearStrategyPressureDebug: () => clearStrategyPressureDebug,
|
|
10594
10696
|
computeDeviation: () => computeDeviation,
|
|
10595
10697
|
computeEffectiveWeight: () => computeEffectiveWeight,
|
|
10596
10698
|
computeOutcomeSignal: () => computeOutcomeSignal,
|
|
@@ -10613,6 +10715,7 @@ __export(index_exports, {
|
|
|
10613
10715
|
getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
|
|
10614
10716
|
getRegisteredNavigatorRole: () => getRegisteredNavigatorRole,
|
|
10615
10717
|
getSrsBacklogDebug: () => getSrsBacklogDebug,
|
|
10718
|
+
getStrategyPressureDebug: () => getStrategyPressureDebug,
|
|
10616
10719
|
getStudySource: () => getStudySource,
|
|
10617
10720
|
hasRegisteredNavigator: () => hasRegisteredNavigator,
|
|
10618
10721
|
importParsedCards: () => importParsedCards,
|
|
@@ -11659,7 +11762,7 @@ var CardHydrationService = class {
|
|
|
11659
11762
|
}
|
|
11660
11763
|
const data = dataDocs.map(import_common25.displayableDataToViewData).reverse();
|
|
11661
11764
|
this.hydratedCards.set(item.cardID, {
|
|
11662
|
-
item,
|
|
11765
|
+
item: { ...item, elo: (0, import_common25.toCourseElo)(cardData.elo).global.score },
|
|
11663
11766
|
view,
|
|
11664
11767
|
data,
|
|
11665
11768
|
tags: tagsByCard.get(item.cardID) ?? []
|
|
@@ -13585,6 +13688,7 @@ mountMixerDebugger();
|
|
|
13585
13688
|
init_logger();
|
|
13586
13689
|
init_PipelineDebugger();
|
|
13587
13690
|
init_SrsDebugger();
|
|
13691
|
+
init_StrategyPressureDebugger();
|
|
13588
13692
|
|
|
13589
13693
|
// src/study/SessionOverlay.ts
|
|
13590
13694
|
init_logger();
|
|
@@ -13675,7 +13779,7 @@ function render() {
|
|
|
13675
13779
|
attachHandlers();
|
|
13676
13780
|
return;
|
|
13677
13781
|
}
|
|
13678
|
-
overlayEl.innerHTML = headerHtml() + replanHtml(s) + metaHtml(s) + hintsHtml(s.sessionHints) + backlogHtml(s.reviewBacklog) + queueHtml("supplyQ", "supplyQ", s.supplyQ) + queueHtml("failedQ", "failedQ", s.failedQ) + drawnHtml("drawn", s.drawnCards);
|
|
13782
|
+
overlayEl.innerHTML = headerHtml() + replanHtml(s) + metaHtml(s) + hintsHtml(s.sessionHints) + backlogHtml(s.reviewBacklog) + strategyPressureHtml(s.strategyPressure) + queueHtml("supplyQ", "supplyQ", s.supplyQ) + queueHtml("failedQ", "failedQ", s.failedQ) + drawnHtml("drawn", s.drawnCards);
|
|
13679
13783
|
attachHandlers();
|
|
13680
13784
|
}
|
|
13681
13785
|
function attachHandlers() {
|
|
@@ -13779,6 +13883,46 @@ function backlogHtml(backlog) {
|
|
|
13779
13883
|
}).join("");
|
|
13780
13884
|
return `<div style="margin-bottom:6px"><div style="color:#93c5fd">review backpressure</div>${rows}</div>`;
|
|
13781
13885
|
}
|
|
13886
|
+
function pressureColor(multiplier, max) {
|
|
13887
|
+
if (multiplier <= 1.001) return "#86efac";
|
|
13888
|
+
if (max !== void 0 && max > 1) {
|
|
13889
|
+
return (multiplier - 1) / (max - 1) >= 0.75 ? "#fca5a5" : "#fcd34d";
|
|
13890
|
+
}
|
|
13891
|
+
return multiplier >= 3 ? "#fca5a5" : "#fcd34d";
|
|
13892
|
+
}
|
|
13893
|
+
function toggleKey(raw) {
|
|
13894
|
+
return raw.replace(/[^\w:.|-]/g, "_");
|
|
13895
|
+
}
|
|
13896
|
+
function gaugeHtml(sectionKey, g) {
|
|
13897
|
+
const cap = g.max !== void 0 ? `<span style="opacity:.5">/${g.max}</span>` : "";
|
|
13898
|
+
const detail = g.detail ? ` <span style="opacity:.6">${esc(g.detail)}</span>` : "";
|
|
13899
|
+
let html = `<div style="margin-left:6px">${esc(g.label)} <span style="color:${pressureColor(g.multiplier, g.max)}">\xD7${g.multiplier.toFixed(2)}</span>${cap}${detail}`;
|
|
13900
|
+
const items = g.items ?? [];
|
|
13901
|
+
if (items.length > 0) {
|
|
13902
|
+
const key = toggleKey(`sp|${sectionKey}|${g.id}`);
|
|
13903
|
+
const isOpen = !!expanded[key];
|
|
13904
|
+
const shown = isOpen ? items : items.slice(0, INLINE_THRESHOLD);
|
|
13905
|
+
html += `<div style="margin-left:6px">` + shown.map(
|
|
13906
|
+
(it) => `<div style="white-space:nowrap;opacity:.75">${esc(it.label)}${it.value ? ` <span style="opacity:.6">${esc(it.value)}</span>` : ""}</div>`
|
|
13907
|
+
).join("");
|
|
13908
|
+
if (items.length > INLINE_THRESHOLD) {
|
|
13909
|
+
const footer = isOpen ? "\u25BE show less" : `\u2026 +${items.length - shown.length} more`;
|
|
13910
|
+
html += `<div data-q="${key}" style="cursor:pointer;opacity:.6">${footer}</div>`;
|
|
13911
|
+
}
|
|
13912
|
+
html += `</div>`;
|
|
13913
|
+
}
|
|
13914
|
+
return html + `</div>`;
|
|
13915
|
+
}
|
|
13916
|
+
function strategyPressureHtml(list) {
|
|
13917
|
+
if (!list.length) return "";
|
|
13918
|
+
const sections = list.map((s) => {
|
|
13919
|
+
const sectionKey = `${s.source}:${s.courseId.slice(0, 8)}`;
|
|
13920
|
+
const top = s.topScore !== null && s.topScore !== void 0 ? s.topScore.toFixed(2) : "\u2014";
|
|
13921
|
+
const hints = s.hintsLabel ? `<div style="margin-left:6px;opacity:.6">hints: ${esc(s.hintsLabel)}</div>` : "";
|
|
13922
|
+
return `<div style="margin-left:6px"><span style="opacity:.7">${esc(s.source)} \xB7 ${esc(s.courseId.slice(0, 8))}</span> <span style="opacity:.6">top score ${top}</span>` + s.gauges.map((g) => gaugeHtml(sectionKey, g)).join("") + hints + `</div>`;
|
|
13923
|
+
}).join("");
|
|
13924
|
+
return `<div style="margin-bottom:6px"><div style="color:#fdba74">strategy backpressure</div>${sections}</div>`;
|
|
13925
|
+
}
|
|
13782
13926
|
function fmtScore(score) {
|
|
13783
13927
|
if (score === void 0) return "";
|
|
13784
13928
|
if (!Number.isFinite(score)) return "REQ";
|
|
@@ -13879,6 +14023,24 @@ function snapshotToText(s) {
|
|
|
13879
14023
|
);
|
|
13880
14024
|
}
|
|
13881
14025
|
}
|
|
14026
|
+
if (s.strategyPressure.length) {
|
|
14027
|
+
lines.push("");
|
|
14028
|
+
lines.push("strategy backpressure:");
|
|
14029
|
+
for (const sp of s.strategyPressure) {
|
|
14030
|
+
const top = sp.topScore !== null && sp.topScore !== void 0 ? sp.topScore.toFixed(2) : "\u2014";
|
|
14031
|
+
lines.push(` ${sp.source} (${sp.courseId.slice(0, 8)}): top score ${top}`);
|
|
14032
|
+
for (const g of sp.gauges) {
|
|
14033
|
+
const cap = g.max !== void 0 ? `/${g.max}` : "";
|
|
14034
|
+
lines.push(
|
|
14035
|
+
` ${g.label} \xD7${g.multiplier.toFixed(2)}${cap}${g.detail ? ` \u2014 ${g.detail}` : ""}`
|
|
14036
|
+
);
|
|
14037
|
+
for (const it of g.items ?? []) {
|
|
14038
|
+
lines.push(` ${it.label}${it.value ? ` (${it.value})` : ""}`);
|
|
14039
|
+
}
|
|
14040
|
+
}
|
|
14041
|
+
if (sp.hintsLabel) lines.push(` hints: ${sp.hintsLabel}`);
|
|
14042
|
+
}
|
|
14043
|
+
}
|
|
13882
14044
|
const queueText = (label, q) => {
|
|
13883
14045
|
lines.push("");
|
|
13884
14046
|
lines.push(`${label}: ${q.length} (drawn ${q.dequeueCount})`);
|
|
@@ -13916,6 +14078,7 @@ var MAX_HISTORY = 5;
|
|
|
13916
14078
|
function clearStaleSessionDebugState() {
|
|
13917
14079
|
clearRunHistory();
|
|
13918
14080
|
clearSrsBacklogDebug();
|
|
14081
|
+
clearStrategyPressureDebug();
|
|
13919
14082
|
}
|
|
13920
14083
|
function startSessionTracking(supplyQLength, failedQLength) {
|
|
13921
14084
|
const sessionId = `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -14604,6 +14767,7 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
14604
14767
|
supplyQ: describe(this.supplyQ),
|
|
14605
14768
|
failedQ: describe(this.failedQ),
|
|
14606
14769
|
reviewBacklog: getSrsBacklogDebug(),
|
|
14770
|
+
strategyPressure: getStrategyPressureDebug(),
|
|
14607
14771
|
drawnCards
|
|
14608
14772
|
};
|
|
14609
14773
|
}
|
|
@@ -15305,8 +15469,10 @@ init_userDBHelpers();
|
|
|
15305
15469
|
areQuestionRecords,
|
|
15306
15470
|
buildStrategyStateId,
|
|
15307
15471
|
captureMixerRun,
|
|
15472
|
+
captureStrategyPressure,
|
|
15308
15473
|
clearSrsBacklogDebug,
|
|
15309
15474
|
clearStaleSessionDebugState,
|
|
15475
|
+
clearStrategyPressureDebug,
|
|
15310
15476
|
computeDeviation,
|
|
15311
15477
|
computeEffectiveWeight,
|
|
15312
15478
|
computeOutcomeSignal,
|
|
@@ -15329,6 +15495,7 @@ init_userDBHelpers();
|
|
|
15329
15495
|
getRegisteredNavigatorNames,
|
|
15330
15496
|
getRegisteredNavigatorRole,
|
|
15331
15497
|
getSrsBacklogDebug,
|
|
15498
|
+
getStrategyPressureDebug,
|
|
15332
15499
|
getStudySource,
|
|
15333
15500
|
hasRegisteredNavigator,
|
|
15334
15501
|
importParsedCards,
|