@vue-skuilder/db 0.2.10 → 0.2.12
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 +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +22 -17
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +22 -17
- package/dist/core/index.mjs.map +1 -1
- package/dist/impl/couch/index.js +22 -17
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +22 -17
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.js +22 -17
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +22 -17
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +68 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +67 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/core/navigators/SrsDebugger.ts +8 -7
- package/src/core/navigators/generators/srs.ts +40 -28
- package/src/study/SessionController.ts +5 -1
- package/src/study/SessionDebugger.ts +16 -8
- package/src/study/SessionOverlay.ts +17 -23
- package/src/study/services/ResponseProcessor.ts +56 -22
package/dist/index.d.cts
CHANGED
|
@@ -1160,6 +1160,18 @@ interface SessionRunReport {
|
|
|
1160
1160
|
presentations: CardPresentation[];
|
|
1161
1161
|
queueSnapshots: QueueSnapshot[];
|
|
1162
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Release pipeline run-history / SRS backlog debug memory from the previous
|
|
1165
|
+
* session before this session begins piling new runs on top of it. Must be
|
|
1166
|
+
* called before the first pipeline run of the new session (including the
|
|
1167
|
+
* bootstrap run in prepareSession) — clearing on session START rather than
|
|
1168
|
+
* END keeps post-session inspection, the dominant debugging workflow, fully
|
|
1169
|
+
* functional: a finished session's run history sits intact until the user
|
|
1170
|
+
* actually begins another one. It's a separate call from startSessionTracking
|
|
1171
|
+
* because that function can't run until supplyQ/failedQ are populated by the
|
|
1172
|
+
* bootstrap pipeline run, which would otherwise be cleared out from under it.
|
|
1173
|
+
*/
|
|
1174
|
+
declare function clearStaleSessionDebugState(): void;
|
|
1163
1175
|
/**
|
|
1164
1176
|
* Start tracking a new session.
|
|
1165
1177
|
*/
|
|
@@ -1467,4 +1479,4 @@ interface CouchDbUserDoc extends PouchDB.Authentication.User {
|
|
|
1467
1479
|
entitlements: UserEntitlements;
|
|
1468
1480
|
}
|
|
1469
1481
|
|
|
1470
|
-
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, SrsBacklogDebug, 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 };
|
|
1482
|
+
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, 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, 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
|
@@ -1160,6 +1160,18 @@ interface SessionRunReport {
|
|
|
1160
1160
|
presentations: CardPresentation[];
|
|
1161
1161
|
queueSnapshots: QueueSnapshot[];
|
|
1162
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Release pipeline run-history / SRS backlog debug memory from the previous
|
|
1165
|
+
* session before this session begins piling new runs on top of it. Must be
|
|
1166
|
+
* called before the first pipeline run of the new session (including the
|
|
1167
|
+
* bootstrap run in prepareSession) — clearing on session START rather than
|
|
1168
|
+
* END keeps post-session inspection, the dominant debugging workflow, fully
|
|
1169
|
+
* functional: a finished session's run history sits intact until the user
|
|
1170
|
+
* actually begins another one. It's a separate call from startSessionTracking
|
|
1171
|
+
* because that function can't run until supplyQ/failedQ are populated by the
|
|
1172
|
+
* bootstrap pipeline run, which would otherwise be cleared out from under it.
|
|
1173
|
+
*/
|
|
1174
|
+
declare function clearStaleSessionDebugState(): void;
|
|
1163
1175
|
/**
|
|
1164
1176
|
* Start tracking a new session.
|
|
1165
1177
|
*/
|
|
@@ -1467,4 +1479,4 @@ interface CouchDbUserDoc extends PouchDB.Authentication.User {
|
|
|
1467
1479
|
entitlements: UserEntitlements;
|
|
1468
1480
|
}
|
|
1469
1481
|
|
|
1470
|
-
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, SrsBacklogDebug, 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 };
|
|
1482
|
+
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, 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, 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.js
CHANGED
|
@@ -2918,7 +2918,7 @@ var srs_exports = {};
|
|
|
2918
2918
|
__export(srs_exports, {
|
|
2919
2919
|
default: () => SRSNavigator
|
|
2920
2920
|
});
|
|
2921
|
-
var import_moment3, DEFAULT_HEALTHY_BACKLOG,
|
|
2921
|
+
var import_moment3, DEFAULT_HEALTHY_BACKLOG, BACKLOG_GROWTH_RATE, SRSNavigator;
|
|
2922
2922
|
var init_srs = __esm({
|
|
2923
2923
|
"src/core/navigators/generators/srs.ts"() {
|
|
2924
2924
|
"use strict";
|
|
@@ -2927,7 +2927,7 @@ var init_srs = __esm({
|
|
|
2927
2927
|
init_SrsDebugger();
|
|
2928
2928
|
init_logger();
|
|
2929
2929
|
DEFAULT_HEALTHY_BACKLOG = 20;
|
|
2930
|
-
|
|
2930
|
+
BACKLOG_GROWTH_RATE = 2;
|
|
2931
2931
|
SRSNavigator = class extends ContentNavigator {
|
|
2932
2932
|
/** Human-readable name for CardGenerator interface */
|
|
2933
2933
|
name;
|
|
@@ -3049,7 +3049,7 @@ var init_srs = __esm({
|
|
|
3049
3049
|
dueNow: dueReviews.length,
|
|
3050
3050
|
healthyBacklog: this.healthyBacklog,
|
|
3051
3051
|
backlogMultiplier,
|
|
3052
|
-
|
|
3052
|
+
backlogGrowthRate: BACKLOG_GROWTH_RATE,
|
|
3053
3053
|
topReviewScore: sorted.length > 0 ? sorted[0].score : null,
|
|
3054
3054
|
nextDueIn,
|
|
3055
3055
|
timestamp: Date.now()
|
|
@@ -3059,25 +3059,30 @@ var init_srs = __esm({
|
|
|
3059
3059
|
/**
|
|
3060
3060
|
* Compute the multiplicative backlog pressure based on number of due reviews.
|
|
3061
3061
|
*
|
|
3062
|
-
* ×1.0 at or below the healthy threshold (no boost),
|
|
3063
|
-
*
|
|
3062
|
+
* ×1.0 at or below the healthy threshold (no boost); above it, grows as
|
|
3063
|
+
* BACKLOG_GROWTH_RATE raised to the excess expressed in multiples of the
|
|
3064
|
+
* healthy threshold. Uncapped — self-regulating instead: reviews winning
|
|
3065
|
+
* slots depletes dueCount, which drops the ratio and relaxes the multiplier
|
|
3066
|
+
* next run.
|
|
3064
3067
|
*
|
|
3065
|
-
* Examples (with default healthyBacklog=20,
|
|
3066
|
-
* - 10 due reviews → ×1.00
|
|
3067
|
-
* - 20 due reviews → ×1.00
|
|
3068
|
-
* - 40 due reviews → ×1.50
|
|
3069
|
-
* - 60 due reviews → ×2.
|
|
3068
|
+
* Examples (with default healthyBacklog=20, BACKLOG_GROWTH_RATE=1.5):
|
|
3069
|
+
* - 10 due reviews → ×1.00 (healthy)
|
|
3070
|
+
* - 20 due reviews → ×1.00 (at threshold, ratio 0)
|
|
3071
|
+
* - 40 due reviews → ×1.50 (ratio 1, 2x threshold)
|
|
3072
|
+
* - 60 due reviews → ×2.25 (ratio 2, 3x threshold — old hard cap was ×2.00 here)
|
|
3073
|
+
* - 100 due reviews → ×5.06 (ratio 4, 5x threshold)
|
|
3074
|
+
* - 160 due reviews → ×17.09 (ratio 7, 8x threshold)
|
|
3070
3075
|
*
|
|
3071
3076
|
* @param dueCount - Number of reviews currently due
|
|
3072
|
-
* @returns Multiplier applied to review urgency (1.0
|
|
3077
|
+
* @returns Multiplier applied to review urgency (>= 1.0, unbounded)
|
|
3073
3078
|
*/
|
|
3074
3079
|
computeBacklogMultiplier(dueCount) {
|
|
3075
3080
|
if (dueCount <= this.healthyBacklog) {
|
|
3076
3081
|
return 1;
|
|
3077
3082
|
}
|
|
3078
3083
|
const excess = dueCount - this.healthyBacklog;
|
|
3079
|
-
const
|
|
3080
|
-
return Math.
|
|
3084
|
+
const ratio = excess / this.healthyBacklog;
|
|
3085
|
+
return Math.pow(BACKLOG_GROWTH_RATE, ratio);
|
|
3081
3086
|
}
|
|
3082
3087
|
/**
|
|
3083
3088
|
* Compute urgency score for a review card.
|
|
@@ -3093,17 +3098,17 @@ var init_srs = __esm({
|
|
|
3093
3098
|
* - 180 days → ~0.30
|
|
3094
3099
|
*
|
|
3095
3100
|
* 3. Backlog pressure = global *multiplier* when review backlog exceeds the
|
|
3096
|
-
* healthy threshold (×1.0 healthy →
|
|
3101
|
+
* healthy threshold (×1.0 healthy → exponential growth, uncapped, above it).
|
|
3097
3102
|
*
|
|
3098
3103
|
* Combined: (base 0.5 + urgency factors * 0.45) × backlog multiplier.
|
|
3099
3104
|
* Per-card range before pressure: ~0.57–0.95. NOT clamped to 1.0 — under a
|
|
3100
3105
|
* heavy backlog reviews scale onto the open scale to compete with (and exceed)
|
|
3101
|
-
* new cards;
|
|
3102
|
-
*
|
|
3106
|
+
* new cards; there's no ceiling at all now, so a bad enough backlog always
|
|
3107
|
+
* wins eventually — self-regulating because winning slots depletes dueCount.
|
|
3103
3108
|
*
|
|
3104
3109
|
* @param review - The scheduled card to score
|
|
3105
3110
|
* @param now - Current time
|
|
3106
|
-
* @param backlogMultiplier - Pre-computed backlog multiplier (1.0
|
|
3111
|
+
* @param backlogMultiplier - Pre-computed backlog multiplier (>= 1.0, unbounded)
|
|
3107
3112
|
*/
|
|
3108
3113
|
computeUrgencyScore(review, now, backlogMultiplier) {
|
|
3109
3114
|
const scheduledAt = import_moment3.default.utc(review.scheduledAt);
|
|
@@ -10568,6 +10573,7 @@ __export(index_exports, {
|
|
|
10568
10573
|
buildStrategyStateId: () => buildStrategyStateId,
|
|
10569
10574
|
captureMixerRun: () => captureMixerRun,
|
|
10570
10575
|
clearSrsBacklogDebug: () => clearSrsBacklogDebug,
|
|
10576
|
+
clearStaleSessionDebugState: () => clearStaleSessionDebugState,
|
|
10571
10577
|
computeDeviation: () => computeDeviation,
|
|
10572
10578
|
computeEffectiveWeight: () => computeEffectiveWeight,
|
|
10573
10579
|
computeOutcomeSignal: () => computeOutcomeSignal,
|
|
@@ -11315,7 +11321,7 @@ var ResponseProcessor = class {
|
|
|
11315
11321
|
const nullTags = tagKeys.filter((k) => taggedPerformance[k] === null);
|
|
11316
11322
|
const scoredTags = tagKeys.filter((k) => taggedPerformance[k] !== null);
|
|
11317
11323
|
logger.info(
|
|
11318
|
-
`[
|
|
11324
|
+
`[FirstContactElo] correct first-attempt per-tag ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps}): scored=[${scoredTags.join(", ")}] count-only=[${nullTags.join(", ")}]`
|
|
11319
11325
|
);
|
|
11320
11326
|
void this.eloService.updateUserAndCardEloPerTag(
|
|
11321
11327
|
taggedPerformance,
|
|
@@ -11346,7 +11352,7 @@ var ResponseProcessor = class {
|
|
|
11346
11352
|
);
|
|
11347
11353
|
}
|
|
11348
11354
|
logger.info(
|
|
11349
|
-
|
|
11355
|
+
`[FirstContactElo] correct first-attempt ELO update (score=${userScore.toFixed(3)}) for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`
|
|
11350
11356
|
);
|
|
11351
11357
|
}
|
|
11352
11358
|
return {
|
|
@@ -11375,7 +11381,8 @@ var ResponseProcessor = class {
|
|
|
11375
11381
|
*/
|
|
11376
11382
|
processIncorrectResponse(cardRecord, history, courseRegistrationDoc, currentCard, courseId, cardId, maxAttemptsPerView, maxSessionViews, sessionViews) {
|
|
11377
11383
|
const { taggedPerformance } = this.parsePerformance(cardRecord.performance);
|
|
11378
|
-
|
|
11384
|
+
let eloUpdated = false;
|
|
11385
|
+
if (cardRecord.priorAttemps === 0) {
|
|
11379
11386
|
if (taggedPerformance) {
|
|
11380
11387
|
void this.eloService.updateUserAndCardEloPerTag(
|
|
11381
11388
|
taggedPerformance,
|
|
@@ -11385,7 +11392,7 @@ var ResponseProcessor = class {
|
|
|
11385
11392
|
currentCard
|
|
11386
11393
|
);
|
|
11387
11394
|
logger.info(
|
|
11388
|
-
`[
|
|
11395
|
+
`[FirstContactElo] incorrect first-attempt per-tag ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps}, tags=${Object.keys(taggedPerformance).length - 1})`
|
|
11389
11396
|
);
|
|
11390
11397
|
} else {
|
|
11391
11398
|
void this.eloService.updateUserAndCardElo(
|
|
@@ -11396,28 +11403,42 @@ var ResponseProcessor = class {
|
|
|
11396
11403
|
courseRegistrationDoc,
|
|
11397
11404
|
currentCard
|
|
11398
11405
|
);
|
|
11399
|
-
logger.info(
|
|
11406
|
+
logger.info(
|
|
11407
|
+
`[FirstContactElo] incorrect first-attempt ELO update (score=0) for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`
|
|
11408
|
+
);
|
|
11400
11409
|
}
|
|
11410
|
+
eloUpdated = true;
|
|
11401
11411
|
} else {
|
|
11402
|
-
logger.info(
|
|
11412
|
+
logger.info(
|
|
11413
|
+
`[FirstContactElo] incorrect retry \u2014 no ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`
|
|
11414
|
+
);
|
|
11403
11415
|
}
|
|
11404
11416
|
if (currentCard.records.length >= maxAttemptsPerView) {
|
|
11405
11417
|
if (sessionViews >= maxSessionViews) {
|
|
11406
|
-
if (
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11418
|
+
if (!eloUpdated) {
|
|
11419
|
+
if (taggedPerformance) {
|
|
11420
|
+
void this.eloService.updateUserAndCardEloPerTag(
|
|
11421
|
+
taggedPerformance,
|
|
11422
|
+
courseId,
|
|
11423
|
+
cardId,
|
|
11424
|
+
courseRegistrationDoc,
|
|
11425
|
+
currentCard
|
|
11426
|
+
);
|
|
11427
|
+
} else {
|
|
11428
|
+
void this.eloService.updateUserAndCardElo(
|
|
11429
|
+
0,
|
|
11430
|
+
courseId,
|
|
11431
|
+
cardId,
|
|
11432
|
+
courseRegistrationDoc,
|
|
11433
|
+
currentCard
|
|
11434
|
+
);
|
|
11435
|
+
}
|
|
11436
|
+
logger.info(
|
|
11437
|
+
`[FirstContactElo] dismiss-failed final ELO penalty for ${cardId} (historyLen=${history.records.length}, sessionViews=${sessionViews})`
|
|
11413
11438
|
);
|
|
11414
11439
|
} else {
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
courseId,
|
|
11418
|
-
cardId,
|
|
11419
|
-
courseRegistrationDoc,
|
|
11420
|
-
currentCard
|
|
11440
|
+
logger.info(
|
|
11441
|
+
`[FirstContactElo] dismiss-failed \u2014 ELO already updated this response, skipping double penalty for ${cardId}`
|
|
11421
11442
|
);
|
|
11422
11443
|
}
|
|
11423
11444
|
return {
|
|
@@ -13722,12 +13743,12 @@ function hintsHtml(h) {
|
|
|
13722
13743
|
function backlogHtml(backlog) {
|
|
13723
13744
|
if (!backlog.length) return "";
|
|
13724
13745
|
const rows = backlog.map((b) => {
|
|
13725
|
-
const
|
|
13726
|
-
const multColor = b.backlogMultiplier <= 1 ? "#86efac" :
|
|
13727
|
-
const headroom =
|
|
13746
|
+
const hot = b.backlogMultiplier >= 3;
|
|
13747
|
+
const multColor = b.backlogMultiplier <= 1 ? "#86efac" : hot ? "#fca5a5" : "#fcd34d";
|
|
13748
|
+
const headroom = b.backlogMultiplier > 1 ? `climbing (\xD7${b.backlogGrowthRate.toFixed(2)} per ${b.healthyBacklog}-review excess, unbounded)` : "healthy \u2014 no pressure";
|
|
13728
13749
|
const top = b.topReviewScore !== null ? b.topReviewScore.toFixed(2) : "\u2014";
|
|
13729
13750
|
const next = b.nextDueIn ? ` <span style="opacity:.6">\xB7 next due ${esc(b.nextDueIn)}</span>` : "";
|
|
13730
|
-
return `<div style="margin-left:6px"><span style="opacity:.7">${esc(b.courseId.slice(0, 8))}</span> due ${b.dueNow}/${b.scheduledTotal} <span style="opacity:.6">(healthy ${b.healthyBacklog})</span>${next}<div style="margin-left:6px">pressure <span style="color:${multColor}">\xD7${b.backlogMultiplier.toFixed(2)}
|
|
13751
|
+
return `<div style="margin-left:6px"><span style="opacity:.7">${esc(b.courseId.slice(0, 8))}</span> due ${b.dueNow}/${b.scheduledTotal} <span style="opacity:.6">(healthy ${b.healthyBacklog})</span>${next}<div style="margin-left:6px">pressure <span style="color:${multColor}">\xD7${b.backlogMultiplier.toFixed(2)}</span> <span style="opacity:.6">${headroom} \xB7 top review ${top}</span></div></div>`;
|
|
13731
13752
|
}).join("");
|
|
13732
13753
|
return `<div style="margin-bottom:6px"><div style="color:#93c5fd">review backpressure</div>${rows}</div>`;
|
|
13733
13754
|
}
|
|
@@ -13823,12 +13844,11 @@ function snapshotToText(s) {
|
|
|
13823
13844
|
lines.push("");
|
|
13824
13845
|
lines.push("review backpressure:");
|
|
13825
13846
|
for (const b of s.reviewBacklog) {
|
|
13826
|
-
const
|
|
13827
|
-
const headroom = maxed ? "maxed (boosts decide order)" : b.backlogMultiplier > 1 ? "climbing" : "healthy";
|
|
13847
|
+
const headroom = b.backlogMultiplier > 1 ? "climbing" : "healthy";
|
|
13828
13848
|
const top = b.topReviewScore !== null ? b.topReviewScore.toFixed(2) : "\u2014";
|
|
13829
13849
|
const next = b.nextDueIn ? `, next due ${b.nextDueIn}` : "";
|
|
13830
13850
|
lines.push(
|
|
13831
|
-
` ${b.courseId.slice(0, 8)}: due ${b.dueNow}/${b.scheduledTotal} (healthy ${b.healthyBacklog})${next}; pressure \xD7${b.backlogMultiplier.toFixed(2)}
|
|
13851
|
+
` ${b.courseId.slice(0, 8)}: due ${b.dueNow}/${b.scheduledTotal} (healthy ${b.healthyBacklog})${next}; pressure \xD7${b.backlogMultiplier.toFixed(2)} ${headroom}; top review ${top}`
|
|
13832
13852
|
);
|
|
13833
13853
|
}
|
|
13834
13854
|
}
|
|
@@ -13866,9 +13886,11 @@ function esc(value) {
|
|
|
13866
13886
|
var activeSession = null;
|
|
13867
13887
|
var sessionHistory = [];
|
|
13868
13888
|
var MAX_HISTORY = 5;
|
|
13869
|
-
function
|
|
13889
|
+
function clearStaleSessionDebugState() {
|
|
13870
13890
|
clearRunHistory();
|
|
13871
13891
|
clearSrsBacklogDebug();
|
|
13892
|
+
}
|
|
13893
|
+
function startSessionTracking(supplyQLength, failedQLength) {
|
|
13872
13894
|
const sessionId = `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
13873
13895
|
activeSession = {
|
|
13874
13896
|
sessionId,
|
|
@@ -14350,6 +14372,7 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
14350
14372
|
"[SessionController] All content sources must implement getWeightedCards()."
|
|
14351
14373
|
);
|
|
14352
14374
|
}
|
|
14375
|
+
clearStaleSessionDebugState();
|
|
14353
14376
|
const wellIndicated = await this.getWeightedContent();
|
|
14354
14377
|
this._wellIndicatedRemaining = wellIndicated;
|
|
14355
14378
|
if (wellIndicated >= 0 && wellIndicated < _SessionController.MIN_WELL_INDICATED) {
|
|
@@ -15254,6 +15277,7 @@ init_factory();
|
|
|
15254
15277
|
buildStrategyStateId,
|
|
15255
15278
|
captureMixerRun,
|
|
15256
15279
|
clearSrsBacklogDebug,
|
|
15280
|
+
clearStaleSessionDebugState,
|
|
15257
15281
|
computeDeviation,
|
|
15258
15282
|
computeEffectiveWeight,
|
|
15259
15283
|
computeOutcomeSignal,
|