@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.mjs
CHANGED
|
@@ -2896,7 +2896,7 @@ __export(srs_exports, {
|
|
|
2896
2896
|
default: () => SRSNavigator
|
|
2897
2897
|
});
|
|
2898
2898
|
import moment3 from "moment";
|
|
2899
|
-
var DEFAULT_HEALTHY_BACKLOG,
|
|
2899
|
+
var DEFAULT_HEALTHY_BACKLOG, BACKLOG_GROWTH_RATE, SRSNavigator;
|
|
2900
2900
|
var init_srs = __esm({
|
|
2901
2901
|
"src/core/navigators/generators/srs.ts"() {
|
|
2902
2902
|
"use strict";
|
|
@@ -2904,7 +2904,7 @@ var init_srs = __esm({
|
|
|
2904
2904
|
init_SrsDebugger();
|
|
2905
2905
|
init_logger();
|
|
2906
2906
|
DEFAULT_HEALTHY_BACKLOG = 20;
|
|
2907
|
-
|
|
2907
|
+
BACKLOG_GROWTH_RATE = 2;
|
|
2908
2908
|
SRSNavigator = class extends ContentNavigator {
|
|
2909
2909
|
/** Human-readable name for CardGenerator interface */
|
|
2910
2910
|
name;
|
|
@@ -3026,7 +3026,7 @@ var init_srs = __esm({
|
|
|
3026
3026
|
dueNow: dueReviews.length,
|
|
3027
3027
|
healthyBacklog: this.healthyBacklog,
|
|
3028
3028
|
backlogMultiplier,
|
|
3029
|
-
|
|
3029
|
+
backlogGrowthRate: BACKLOG_GROWTH_RATE,
|
|
3030
3030
|
topReviewScore: sorted.length > 0 ? sorted[0].score : null,
|
|
3031
3031
|
nextDueIn,
|
|
3032
3032
|
timestamp: Date.now()
|
|
@@ -3036,25 +3036,30 @@ var init_srs = __esm({
|
|
|
3036
3036
|
/**
|
|
3037
3037
|
* Compute the multiplicative backlog pressure based on number of due reviews.
|
|
3038
3038
|
*
|
|
3039
|
-
* ×1.0 at or below the healthy threshold (no boost),
|
|
3040
|
-
*
|
|
3039
|
+
* ×1.0 at or below the healthy threshold (no boost); above it, grows as
|
|
3040
|
+
* BACKLOG_GROWTH_RATE raised to the excess expressed in multiples of the
|
|
3041
|
+
* healthy threshold. Uncapped — self-regulating instead: reviews winning
|
|
3042
|
+
* slots depletes dueCount, which drops the ratio and relaxes the multiplier
|
|
3043
|
+
* next run.
|
|
3041
3044
|
*
|
|
3042
|
-
* Examples (with default healthyBacklog=20,
|
|
3043
|
-
* - 10 due reviews → ×1.00
|
|
3044
|
-
* - 20 due reviews → ×1.00
|
|
3045
|
-
* - 40 due reviews → ×1.50
|
|
3046
|
-
* - 60 due reviews → ×2.
|
|
3045
|
+
* Examples (with default healthyBacklog=20, BACKLOG_GROWTH_RATE=1.5):
|
|
3046
|
+
* - 10 due reviews → ×1.00 (healthy)
|
|
3047
|
+
* - 20 due reviews → ×1.00 (at threshold, ratio 0)
|
|
3048
|
+
* - 40 due reviews → ×1.50 (ratio 1, 2x threshold)
|
|
3049
|
+
* - 60 due reviews → ×2.25 (ratio 2, 3x threshold — old hard cap was ×2.00 here)
|
|
3050
|
+
* - 100 due reviews → ×5.06 (ratio 4, 5x threshold)
|
|
3051
|
+
* - 160 due reviews → ×17.09 (ratio 7, 8x threshold)
|
|
3047
3052
|
*
|
|
3048
3053
|
* @param dueCount - Number of reviews currently due
|
|
3049
|
-
* @returns Multiplier applied to review urgency (1.0
|
|
3054
|
+
* @returns Multiplier applied to review urgency (>= 1.0, unbounded)
|
|
3050
3055
|
*/
|
|
3051
3056
|
computeBacklogMultiplier(dueCount) {
|
|
3052
3057
|
if (dueCount <= this.healthyBacklog) {
|
|
3053
3058
|
return 1;
|
|
3054
3059
|
}
|
|
3055
3060
|
const excess = dueCount - this.healthyBacklog;
|
|
3056
|
-
const
|
|
3057
|
-
return Math.
|
|
3061
|
+
const ratio = excess / this.healthyBacklog;
|
|
3062
|
+
return Math.pow(BACKLOG_GROWTH_RATE, ratio);
|
|
3058
3063
|
}
|
|
3059
3064
|
/**
|
|
3060
3065
|
* Compute urgency score for a review card.
|
|
@@ -3070,17 +3075,17 @@ var init_srs = __esm({
|
|
|
3070
3075
|
* - 180 days → ~0.30
|
|
3071
3076
|
*
|
|
3072
3077
|
* 3. Backlog pressure = global *multiplier* when review backlog exceeds the
|
|
3073
|
-
* healthy threshold (×1.0 healthy →
|
|
3078
|
+
* healthy threshold (×1.0 healthy → exponential growth, uncapped, above it).
|
|
3074
3079
|
*
|
|
3075
3080
|
* Combined: (base 0.5 + urgency factors * 0.45) × backlog multiplier.
|
|
3076
3081
|
* Per-card range before pressure: ~0.57–0.95. NOT clamped to 1.0 — under a
|
|
3077
3082
|
* heavy backlog reviews scale onto the open scale to compete with (and exceed)
|
|
3078
|
-
* new cards;
|
|
3079
|
-
*
|
|
3083
|
+
* new cards; there's no ceiling at all now, so a bad enough backlog always
|
|
3084
|
+
* wins eventually — self-regulating because winning slots depletes dueCount.
|
|
3080
3085
|
*
|
|
3081
3086
|
* @param review - The scheduled card to score
|
|
3082
3087
|
* @param now - Current time
|
|
3083
|
-
* @param backlogMultiplier - Pre-computed backlog multiplier (1.0
|
|
3088
|
+
* @param backlogMultiplier - Pre-computed backlog multiplier (>= 1.0, unbounded)
|
|
3084
3089
|
*/
|
|
3085
3090
|
computeUrgencyScore(review, now, backlogMultiplier) {
|
|
3086
3091
|
const scheduledAt = moment3.utc(review.scheduledAt);
|
|
@@ -11203,7 +11208,7 @@ var ResponseProcessor = class {
|
|
|
11203
11208
|
const nullTags = tagKeys.filter((k) => taggedPerformance[k] === null);
|
|
11204
11209
|
const scoredTags = tagKeys.filter((k) => taggedPerformance[k] !== null);
|
|
11205
11210
|
logger.info(
|
|
11206
|
-
`[
|
|
11211
|
+
`[FirstContactElo] correct first-attempt per-tag ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps}): scored=[${scoredTags.join(", ")}] count-only=[${nullTags.join(", ")}]`
|
|
11207
11212
|
);
|
|
11208
11213
|
void this.eloService.updateUserAndCardEloPerTag(
|
|
11209
11214
|
taggedPerformance,
|
|
@@ -11234,7 +11239,7 @@ var ResponseProcessor = class {
|
|
|
11234
11239
|
);
|
|
11235
11240
|
}
|
|
11236
11241
|
logger.info(
|
|
11237
|
-
|
|
11242
|
+
`[FirstContactElo] correct first-attempt ELO update (score=${userScore.toFixed(3)}) for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`
|
|
11238
11243
|
);
|
|
11239
11244
|
}
|
|
11240
11245
|
return {
|
|
@@ -11263,7 +11268,8 @@ var ResponseProcessor = class {
|
|
|
11263
11268
|
*/
|
|
11264
11269
|
processIncorrectResponse(cardRecord, history, courseRegistrationDoc, currentCard, courseId, cardId, maxAttemptsPerView, maxSessionViews, sessionViews) {
|
|
11265
11270
|
const { taggedPerformance } = this.parsePerformance(cardRecord.performance);
|
|
11266
|
-
|
|
11271
|
+
let eloUpdated = false;
|
|
11272
|
+
if (cardRecord.priorAttemps === 0) {
|
|
11267
11273
|
if (taggedPerformance) {
|
|
11268
11274
|
void this.eloService.updateUserAndCardEloPerTag(
|
|
11269
11275
|
taggedPerformance,
|
|
@@ -11273,7 +11279,7 @@ var ResponseProcessor = class {
|
|
|
11273
11279
|
currentCard
|
|
11274
11280
|
);
|
|
11275
11281
|
logger.info(
|
|
11276
|
-
`[
|
|
11282
|
+
`[FirstContactElo] incorrect first-attempt per-tag ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps}, tags=${Object.keys(taggedPerformance).length - 1})`
|
|
11277
11283
|
);
|
|
11278
11284
|
} else {
|
|
11279
11285
|
void this.eloService.updateUserAndCardElo(
|
|
@@ -11284,28 +11290,42 @@ var ResponseProcessor = class {
|
|
|
11284
11290
|
courseRegistrationDoc,
|
|
11285
11291
|
currentCard
|
|
11286
11292
|
);
|
|
11287
|
-
logger.info(
|
|
11293
|
+
logger.info(
|
|
11294
|
+
`[FirstContactElo] incorrect first-attempt ELO update (score=0) for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`
|
|
11295
|
+
);
|
|
11288
11296
|
}
|
|
11297
|
+
eloUpdated = true;
|
|
11289
11298
|
} else {
|
|
11290
|
-
logger.info(
|
|
11299
|
+
logger.info(
|
|
11300
|
+
`[FirstContactElo] incorrect retry \u2014 no ELO update for ${cardId} (historyLen=${history.records.length}, priorAttemps=${cardRecord.priorAttemps})`
|
|
11301
|
+
);
|
|
11291
11302
|
}
|
|
11292
11303
|
if (currentCard.records.length >= maxAttemptsPerView) {
|
|
11293
11304
|
if (sessionViews >= maxSessionViews) {
|
|
11294
|
-
if (
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
11305
|
+
if (!eloUpdated) {
|
|
11306
|
+
if (taggedPerformance) {
|
|
11307
|
+
void this.eloService.updateUserAndCardEloPerTag(
|
|
11308
|
+
taggedPerformance,
|
|
11309
|
+
courseId,
|
|
11310
|
+
cardId,
|
|
11311
|
+
courseRegistrationDoc,
|
|
11312
|
+
currentCard
|
|
11313
|
+
);
|
|
11314
|
+
} else {
|
|
11315
|
+
void this.eloService.updateUserAndCardElo(
|
|
11316
|
+
0,
|
|
11317
|
+
courseId,
|
|
11318
|
+
cardId,
|
|
11319
|
+
courseRegistrationDoc,
|
|
11320
|
+
currentCard
|
|
11321
|
+
);
|
|
11322
|
+
}
|
|
11323
|
+
logger.info(
|
|
11324
|
+
`[FirstContactElo] dismiss-failed final ELO penalty for ${cardId} (historyLen=${history.records.length}, sessionViews=${sessionViews})`
|
|
11301
11325
|
);
|
|
11302
11326
|
} else {
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
courseId,
|
|
11306
|
-
cardId,
|
|
11307
|
-
courseRegistrationDoc,
|
|
11308
|
-
currentCard
|
|
11327
|
+
logger.info(
|
|
11328
|
+
`[FirstContactElo] dismiss-failed \u2014 ELO already updated this response, skipping double penalty for ${cardId}`
|
|
11309
11329
|
);
|
|
11310
11330
|
}
|
|
11311
11331
|
return {
|
|
@@ -13614,12 +13634,12 @@ function hintsHtml(h) {
|
|
|
13614
13634
|
function backlogHtml(backlog) {
|
|
13615
13635
|
if (!backlog.length) return "";
|
|
13616
13636
|
const rows = backlog.map((b) => {
|
|
13617
|
-
const
|
|
13618
|
-
const multColor = b.backlogMultiplier <= 1 ? "#86efac" :
|
|
13619
|
-
const headroom =
|
|
13637
|
+
const hot = b.backlogMultiplier >= 3;
|
|
13638
|
+
const multColor = b.backlogMultiplier <= 1 ? "#86efac" : hot ? "#fca5a5" : "#fcd34d";
|
|
13639
|
+
const headroom = b.backlogMultiplier > 1 ? `climbing (\xD7${b.backlogGrowthRate.toFixed(2)} per ${b.healthyBacklog}-review excess, unbounded)` : "healthy \u2014 no pressure";
|
|
13620
13640
|
const top = b.topReviewScore !== null ? b.topReviewScore.toFixed(2) : "\u2014";
|
|
13621
13641
|
const next = b.nextDueIn ? ` <span style="opacity:.6">\xB7 next due ${esc(b.nextDueIn)}</span>` : "";
|
|
13622
|
-
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)}
|
|
13642
|
+
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>`;
|
|
13623
13643
|
}).join("");
|
|
13624
13644
|
return `<div style="margin-bottom:6px"><div style="color:#93c5fd">review backpressure</div>${rows}</div>`;
|
|
13625
13645
|
}
|
|
@@ -13715,12 +13735,11 @@ function snapshotToText(s) {
|
|
|
13715
13735
|
lines.push("");
|
|
13716
13736
|
lines.push("review backpressure:");
|
|
13717
13737
|
for (const b of s.reviewBacklog) {
|
|
13718
|
-
const
|
|
13719
|
-
const headroom = maxed ? "maxed (boosts decide order)" : b.backlogMultiplier > 1 ? "climbing" : "healthy";
|
|
13738
|
+
const headroom = b.backlogMultiplier > 1 ? "climbing" : "healthy";
|
|
13720
13739
|
const top = b.topReviewScore !== null ? b.topReviewScore.toFixed(2) : "\u2014";
|
|
13721
13740
|
const next = b.nextDueIn ? `, next due ${b.nextDueIn}` : "";
|
|
13722
13741
|
lines.push(
|
|
13723
|
-
` ${b.courseId.slice(0, 8)}: due ${b.dueNow}/${b.scheduledTotal} (healthy ${b.healthyBacklog})${next}; pressure \xD7${b.backlogMultiplier.toFixed(2)}
|
|
13742
|
+
` ${b.courseId.slice(0, 8)}: due ${b.dueNow}/${b.scheduledTotal} (healthy ${b.healthyBacklog})${next}; pressure \xD7${b.backlogMultiplier.toFixed(2)} ${headroom}; top review ${top}`
|
|
13724
13743
|
);
|
|
13725
13744
|
}
|
|
13726
13745
|
}
|
|
@@ -13758,9 +13777,11 @@ function esc(value) {
|
|
|
13758
13777
|
var activeSession = null;
|
|
13759
13778
|
var sessionHistory = [];
|
|
13760
13779
|
var MAX_HISTORY = 5;
|
|
13761
|
-
function
|
|
13780
|
+
function clearStaleSessionDebugState() {
|
|
13762
13781
|
clearRunHistory();
|
|
13763
13782
|
clearSrsBacklogDebug();
|
|
13783
|
+
}
|
|
13784
|
+
function startSessionTracking(supplyQLength, failedQLength) {
|
|
13764
13785
|
const sessionId = `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
13765
13786
|
activeSession = {
|
|
13766
13787
|
sessionId,
|
|
@@ -14242,6 +14263,7 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
14242
14263
|
"[SessionController] All content sources must implement getWeightedCards()."
|
|
14243
14264
|
);
|
|
14244
14265
|
}
|
|
14266
|
+
clearStaleSessionDebugState();
|
|
14245
14267
|
const wellIndicated = await this.getWeightedContent();
|
|
14246
14268
|
this._wellIndicatedRemaining = wellIndicated;
|
|
14247
14269
|
if (wellIndicated >= 0 && wellIndicated < _SessionController.MIN_WELL_INDICATED) {
|
|
@@ -15145,6 +15167,7 @@ export {
|
|
|
15145
15167
|
buildStrategyStateId,
|
|
15146
15168
|
captureMixerRun,
|
|
15147
15169
|
clearSrsBacklogDebug,
|
|
15170
|
+
clearStaleSessionDebugState,
|
|
15148
15171
|
computeDeviation,
|
|
15149
15172
|
computeEffectiveWeight,
|
|
15150
15173
|
computeOutcomeSignal,
|