@vue-skuilder/db 0.2.16 → 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.
@@ -1588,6 +1588,30 @@ var init_SrsDebugger = __esm({
1588
1588
  }
1589
1589
  });
1590
1590
 
1591
+ // src/core/navigators/StrategyPressureDebugger.ts
1592
+ var StrategyPressureDebugger_exports = {};
1593
+ __export(StrategyPressureDebugger_exports, {
1594
+ captureStrategyPressure: () => captureStrategyPressure,
1595
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
1596
+ getStrategyPressureDebug: () => getStrategyPressureDebug
1597
+ });
1598
+ function captureStrategyPressure(snapshot) {
1599
+ snapshots2.set(`${snapshot.source}:${snapshot.courseId}`, snapshot);
1600
+ }
1601
+ function getStrategyPressureDebug() {
1602
+ return [...snapshots2.values()].sort((a, b) => b.timestamp - a.timestamp);
1603
+ }
1604
+ function clearStrategyPressureDebug() {
1605
+ snapshots2.clear();
1606
+ }
1607
+ var snapshots2;
1608
+ var init_StrategyPressureDebugger = __esm({
1609
+ "src/core/navigators/StrategyPressureDebugger.ts"() {
1610
+ "use strict";
1611
+ snapshots2 = /* @__PURE__ */ new Map();
1612
+ }
1613
+ });
1614
+
1591
1615
  // src/core/navigators/generators/CompositeGenerator.ts
1592
1616
  var CompositeGenerator_exports = {};
1593
1617
  __export(CompositeGenerator_exports, {
@@ -1952,6 +1976,13 @@ function shuffleInPlace(arr) {
1952
1976
  [arr[i], arr[j]] = [arr[j], arr[i]];
1953
1977
  }
1954
1978
  }
1979
+ function formatAge(ms) {
1980
+ const minutes = Math.max(0, Math.round(ms / 6e4));
1981
+ if (minutes < 60) return `${minutes}m`;
1982
+ const hours = Math.round(minutes / 60);
1983
+ if (hours < 24) return `${hours}h`;
1984
+ return `${Math.round(hours / 24)}d`;
1985
+ }
1955
1986
  function pickTopByScore(cards, limit) {
1956
1987
  return [...cards].sort((a, b) => b.score - a.score || a.cardId.localeCompare(b.cardId)).slice(0, limit);
1957
1988
  }
@@ -1960,6 +1991,7 @@ var init_prescribed = __esm({
1960
1991
  "src/core/navigators/generators/prescribed.ts"() {
1961
1992
  "use strict";
1962
1993
  init_navigators();
1994
+ init_StrategyPressureDebugger();
1963
1995
  init_logger();
1964
1996
  DEFAULT_FRESHNESS_WINDOW = 3;
1965
1997
  DEFAULT_MAX_DIRECT_PER_RUN = 3;
@@ -2036,6 +2068,7 @@ var init_prescribed = __esm({
2036
2068
  const groupRuntimes = [];
2037
2069
  const priorPracticeDebt = progress.practiceDebt ?? {};
2038
2070
  const nextPracticeDebt = {};
2071
+ const practiceDebtsByGroup = /* @__PURE__ */ new Map();
2039
2072
  for (const group of this.config.groups) {
2040
2073
  const runtime = this.buildGroupRuntimeState({
2041
2074
  group,
@@ -2084,7 +2117,7 @@ var init_prescribed = __esm({
2084
2117
  courseId,
2085
2118
  emittedIds
2086
2119
  );
2087
- const practiceCards = this.buildPracticeCards({
2120
+ const practice = this.buildPracticeCards({
2088
2121
  group,
2089
2122
  courseId,
2090
2123
  emittedIds,
@@ -2097,7 +2130,8 @@ var init_prescribed = __esm({
2097
2130
  priorPracticeDebt,
2098
2131
  nextPracticeDebt
2099
2132
  });
2100
- emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practiceCards);
2133
+ practiceDebtsByGroup.set(group.id, practice.debts);
2134
+ emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practice.cards);
2101
2135
  }
2102
2136
  nextState.practiceDebt = nextPracticeDebt;
2103
2137
  const hintSummary = this.buildSupportHintSummary(groupRuntimes);
@@ -2113,6 +2147,7 @@ var init_prescribed = __esm({
2113
2147
  } else {
2114
2148
  logger.info("[Prescribed] No hints to emit (no blocked targets or no support tags)");
2115
2149
  }
2150
+ this.capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints);
2116
2151
  if (emitted.length === 0) {
2117
2152
  logger.info(
2118
2153
  "[Prescribed] 0 cards emitted (all targets blocked, authored/discovered support candidates exhausted)" + (hints ? " \u2014 boost hints emitted but may not survive filters" : "")
@@ -2174,6 +2209,60 @@ var init_prescribed = __esm({
2174
2209
  supportTags: [...supportTags].sort()
2175
2210
  };
2176
2211
  }
2212
+ /**
2213
+ * Translate this run's per-group runtimes and practice debts into gauges on
2214
+ * the generic strategy-pressure debug channel (rendered by the live session
2215
+ * overlay's "strategy backpressure" section).
2216
+ */
2217
+ capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints) {
2218
+ const now = Date.now();
2219
+ const gauges = [];
2220
+ for (const runtime of groupRuntimes) {
2221
+ const group = runtime.group;
2222
+ const window2 = group.freshnessWindowSessions ?? DEFAULT_FRESHNESS_WINDOW;
2223
+ gauges.push({
2224
+ id: `group:${group.id}:target`,
2225
+ label: `${group.id} targets`,
2226
+ multiplier: runtime.pressureMultiplier,
2227
+ max: MAX_TARGET_MULTIPLIER,
2228
+ detail: `${runtime.pendingTargets.length} pending (${runtime.surfaceableTargets.length} surfaceable, ${runtime.blockedTargets.length} blocked) \xB7 sinceSurfaced ${runtime.sessionsSinceSurfaced}/${window2}`,
2229
+ items: runtime.blockedTargets.map((cardId) => ({ label: cardId, value: "blocked" }))
2230
+ });
2231
+ if (runtime.blockedTargets.length > 0) {
2232
+ const mode = runtime.supportCandidates.length > 0 ? "direct-support" : runtime.discoveredSupportCandidates.length > 0 ? "inserted-support" : "boost-only";
2233
+ gauges.push({
2234
+ id: `group:${group.id}:support`,
2235
+ label: `${group.id} support`,
2236
+ multiplier: runtime.supportMultiplier,
2237
+ max: MAX_SUPPORT_MULTIPLIER,
2238
+ detail: `mode=${mode} \xB7 ${runtime.supportTags.length} support tag(s)`,
2239
+ items: runtime.supportTags.map((tag) => ({ label: tag }))
2240
+ });
2241
+ }
2242
+ const debts = practiceDebtsByGroup.get(group.id) ?? [];
2243
+ if (debts.length > 0) {
2244
+ gauges.push({
2245
+ id: `group:${group.id}:practice-debt`,
2246
+ label: `${group.id} practice debt`,
2247
+ multiplier: Math.max(...debts.map((d) => d.multiplier)),
2248
+ max: MAX_PRACTICE_MULTIPLIER,
2249
+ detail: `${debts.length} under-practiced skill(s)`,
2250
+ items: debts.map((d) => ({
2251
+ label: d.tag,
2252
+ value: `\xD7${d.multiplier.toFixed(2)} \xB7 open ${formatAge(now - new Date(d.firstOwedAt).getTime())}`
2253
+ }))
2254
+ });
2255
+ }
2256
+ }
2257
+ captureStrategyPressure({
2258
+ source: "prescribed",
2259
+ courseId,
2260
+ gauges,
2261
+ topScore: emitted.length > 0 ? Math.max(...emitted.map((c) => c.score)) : null,
2262
+ hintsLabel: hints?._label,
2263
+ timestamp: now
2264
+ });
2265
+ }
2177
2266
  parseConfig(serializedData) {
2178
2267
  try {
2179
2268
  const parsed = JSON.parse(serializedData);
@@ -2330,6 +2419,7 @@ var init_prescribed = __esm({
2330
2419
  supportTags: [...supportTags],
2331
2420
  pressureMultiplier,
2332
2421
  supportMultiplier,
2422
+ sessionsSinceSurfaced,
2333
2423
  debugVersion: PRESCRIBED_DEBUG_VERSION
2334
2424
  };
2335
2425
  }
@@ -2462,13 +2552,13 @@ var init_prescribed = __esm({
2462
2552
  nextPracticeDebt
2463
2553
  } = args;
2464
2554
  const patterns = group.practiceTagPatterns ?? [];
2465
- if (patterns.length === 0) return [];
2555
+ if (patterns.length === 0) return { cards: [], debts: [] };
2466
2556
  const practiceMinCount = group.practiceMinCount ?? DEFAULT_PRACTICE_MIN_COUNT;
2467
2557
  const maxPractice = group.maxPracticeCardsPerRun ?? DEFAULT_MAX_PRACTICE_PER_RUN;
2468
2558
  const practiceTags = [...cardsByTag.keys()].filter(
2469
2559
  (tag) => patterns.some((p) => matchesTagPattern(tag, p)) && this.isUnlockedGatedSkill(tag, hierarchyConfigs, userTagElo, userGlobalElo) && (userTagElo[tag]?.count ?? 0) < practiceMinCount
2470
2560
  );
2471
- if (practiceTags.length === 0) return [];
2561
+ if (practiceTags.length === 0) return { cards: [], debts: [] };
2472
2562
  const now = Date.now();
2473
2563
  const DAY_MS = 24 * 60 * 60 * 1e3;
2474
2564
  const tagMultiplier = /* @__PURE__ */ new Map();
@@ -2483,6 +2573,11 @@ var init_prescribed = __esm({
2483
2573
  );
2484
2574
  tagMultiplier.set(tag, mult);
2485
2575
  }
2576
+ const debts = practiceTags.map((tag) => ({
2577
+ tag,
2578
+ multiplier: tagMultiplier.get(tag) ?? PRACTICE_BASE_MULT,
2579
+ firstOwedAt: nextPracticeDebt[tag]
2580
+ })).sort((a, b) => b.multiplier - a.multiplier || a.tag.localeCompare(b.tag));
2486
2581
  const practiceCardIds = this.findDiscoveredSupportCards({
2487
2582
  supportTags: practiceTags,
2488
2583
  cardsByTag,
@@ -2491,7 +2586,7 @@ var init_prescribed = __esm({
2491
2586
  excludedIds: emittedIds,
2492
2587
  limit: maxPractice
2493
2588
  });
2494
- if (practiceCardIds.length === 0) return [];
2589
+ if (practiceCardIds.length === 0) return { cards: [], debts };
2495
2590
  logger.info(
2496
2591
  `[Prescribed] Group '${group.id}' practice: ${practiceTags.length} unlocked under-practiced skill(s), emitting ${practiceCardIds.length} drill card(s)`
2497
2592
  );
@@ -2521,7 +2616,7 @@ var init_prescribed = __esm({
2521
2616
  ]
2522
2617
  });
2523
2618
  }
2524
- return cards;
2619
+ return { cards, debts };
2525
2620
  }
2526
2621
  /**
2527
2622
  * True for a skill that was *gated and is now reached*: it has at least one
@@ -4952,6 +5047,7 @@ var init_3 = __esm({
4952
5047
  "./PipelineAssembler.ts": () => Promise.resolve().then(() => (init_PipelineAssembler(), PipelineAssembler_exports)),
4953
5048
  "./PipelineDebugger.ts": () => Promise.resolve().then(() => (init_PipelineDebugger(), PipelineDebugger_exports)),
4954
5049
  "./SrsDebugger.ts": () => Promise.resolve().then(() => (init_SrsDebugger(), SrsDebugger_exports)),
5050
+ "./StrategyPressureDebugger.ts": () => Promise.resolve().then(() => (init_StrategyPressureDebugger(), StrategyPressureDebugger_exports)),
4955
5051
  "./defaults.ts": () => Promise.resolve().then(() => (init_defaults(), defaults_exports)),
4956
5052
  "./diversityRerank.ts": () => Promise.resolve().then(() => (init_diversityRerank(), diversityRerank_exports)),
4957
5053
  "./filters/WeightedFilter.ts": () => Promise.resolve().then(() => (init_WeightedFilter(), WeightedFilter_exports)),
@@ -4984,7 +5080,9 @@ __export(navigators_exports, {
4984
5080
  NavigatorRole: () => NavigatorRole,
4985
5081
  NavigatorRoles: () => NavigatorRoles,
4986
5082
  Navigators: () => Navigators,
5083
+ captureStrategyPressure: () => captureStrategyPressure,
4987
5084
  clearSrsBacklogDebug: () => clearSrsBacklogDebug,
5085
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
4988
5086
  diversityRerank: () => diversityRerank,
4989
5087
  getActivePipeline: () => getActivePipeline,
4990
5088
  getCardOrigin: () => getCardOrigin,
@@ -4992,6 +5090,7 @@ __export(navigators_exports, {
4992
5090
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
4993
5091
  getRegisteredNavigatorRole: () => getRegisteredNavigatorRole,
4994
5092
  getSrsBacklogDebug: () => getSrsBacklogDebug,
5093
+ getStrategyPressureDebug: () => getStrategyPressureDebug,
4995
5094
  hasRegisteredNavigator: () => hasRegisteredNavigator,
4996
5095
  initializeNavigatorRegistry: () => initializeNavigatorRegistry,
4997
5096
  isFilter: () => isFilter,
@@ -5074,6 +5173,7 @@ var init_navigators = __esm({
5074
5173
  init_diversityRerank();
5075
5174
  init_PipelineDebugger();
5076
5175
  init_SrsDebugger();
5176
+ init_StrategyPressureDebugger();
5077
5177
  init_logger();
5078
5178
  init_();
5079
5179
  init_2();