@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.
@@ -1566,6 +1566,30 @@ var init_SrsDebugger = __esm({
1566
1566
  }
1567
1567
  });
1568
1568
 
1569
+ // src/core/navigators/StrategyPressureDebugger.ts
1570
+ var StrategyPressureDebugger_exports = {};
1571
+ __export(StrategyPressureDebugger_exports, {
1572
+ captureStrategyPressure: () => captureStrategyPressure,
1573
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
1574
+ getStrategyPressureDebug: () => getStrategyPressureDebug
1575
+ });
1576
+ function captureStrategyPressure(snapshot) {
1577
+ snapshots2.set(`${snapshot.source}:${snapshot.courseId}`, snapshot);
1578
+ }
1579
+ function getStrategyPressureDebug() {
1580
+ return [...snapshots2.values()].sort((a, b) => b.timestamp - a.timestamp);
1581
+ }
1582
+ function clearStrategyPressureDebug() {
1583
+ snapshots2.clear();
1584
+ }
1585
+ var snapshots2;
1586
+ var init_StrategyPressureDebugger = __esm({
1587
+ "src/core/navigators/StrategyPressureDebugger.ts"() {
1588
+ "use strict";
1589
+ snapshots2 = /* @__PURE__ */ new Map();
1590
+ }
1591
+ });
1592
+
1569
1593
  // src/core/navigators/generators/CompositeGenerator.ts
1570
1594
  var CompositeGenerator_exports = {};
1571
1595
  __export(CompositeGenerator_exports, {
@@ -1930,6 +1954,13 @@ function shuffleInPlace(arr) {
1930
1954
  [arr[i], arr[j]] = [arr[j], arr[i]];
1931
1955
  }
1932
1956
  }
1957
+ function formatAge(ms) {
1958
+ const minutes = Math.max(0, Math.round(ms / 6e4));
1959
+ if (minutes < 60) return `${minutes}m`;
1960
+ const hours = Math.round(minutes / 60);
1961
+ if (hours < 24) return `${hours}h`;
1962
+ return `${Math.round(hours / 24)}d`;
1963
+ }
1933
1964
  function pickTopByScore(cards, limit) {
1934
1965
  return [...cards].sort((a, b) => b.score - a.score || a.cardId.localeCompare(b.cardId)).slice(0, limit);
1935
1966
  }
@@ -1938,6 +1969,7 @@ var init_prescribed = __esm({
1938
1969
  "src/core/navigators/generators/prescribed.ts"() {
1939
1970
  "use strict";
1940
1971
  init_navigators();
1972
+ init_StrategyPressureDebugger();
1941
1973
  init_logger();
1942
1974
  DEFAULT_FRESHNESS_WINDOW = 3;
1943
1975
  DEFAULT_MAX_DIRECT_PER_RUN = 3;
@@ -2014,6 +2046,7 @@ var init_prescribed = __esm({
2014
2046
  const groupRuntimes = [];
2015
2047
  const priorPracticeDebt = progress.practiceDebt ?? {};
2016
2048
  const nextPracticeDebt = {};
2049
+ const practiceDebtsByGroup = /* @__PURE__ */ new Map();
2017
2050
  for (const group of this.config.groups) {
2018
2051
  const runtime = this.buildGroupRuntimeState({
2019
2052
  group,
@@ -2062,7 +2095,7 @@ var init_prescribed = __esm({
2062
2095
  courseId,
2063
2096
  emittedIds
2064
2097
  );
2065
- const practiceCards = this.buildPracticeCards({
2098
+ const practice = this.buildPracticeCards({
2066
2099
  group,
2067
2100
  courseId,
2068
2101
  emittedIds,
@@ -2075,7 +2108,8 @@ var init_prescribed = __esm({
2075
2108
  priorPracticeDebt,
2076
2109
  nextPracticeDebt
2077
2110
  });
2078
- emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practiceCards);
2111
+ practiceDebtsByGroup.set(group.id, practice.debts);
2112
+ emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practice.cards);
2079
2113
  }
2080
2114
  nextState.practiceDebt = nextPracticeDebt;
2081
2115
  const hintSummary = this.buildSupportHintSummary(groupRuntimes);
@@ -2091,6 +2125,7 @@ var init_prescribed = __esm({
2091
2125
  } else {
2092
2126
  logger.info("[Prescribed] No hints to emit (no blocked targets or no support tags)");
2093
2127
  }
2128
+ this.capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints);
2094
2129
  if (emitted.length === 0) {
2095
2130
  logger.info(
2096
2131
  "[Prescribed] 0 cards emitted (all targets blocked, authored/discovered support candidates exhausted)" + (hints ? " \u2014 boost hints emitted but may not survive filters" : "")
@@ -2152,6 +2187,60 @@ var init_prescribed = __esm({
2152
2187
  supportTags: [...supportTags].sort()
2153
2188
  };
2154
2189
  }
2190
+ /**
2191
+ * Translate this run's per-group runtimes and practice debts into gauges on
2192
+ * the generic strategy-pressure debug channel (rendered by the live session
2193
+ * overlay's "strategy backpressure" section).
2194
+ */
2195
+ capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints) {
2196
+ const now = Date.now();
2197
+ const gauges = [];
2198
+ for (const runtime of groupRuntimes) {
2199
+ const group = runtime.group;
2200
+ const window2 = group.freshnessWindowSessions ?? DEFAULT_FRESHNESS_WINDOW;
2201
+ gauges.push({
2202
+ id: `group:${group.id}:target`,
2203
+ label: `${group.id} targets`,
2204
+ multiplier: runtime.pressureMultiplier,
2205
+ max: MAX_TARGET_MULTIPLIER,
2206
+ detail: `${runtime.pendingTargets.length} pending (${runtime.surfaceableTargets.length} surfaceable, ${runtime.blockedTargets.length} blocked) \xB7 sinceSurfaced ${runtime.sessionsSinceSurfaced}/${window2}`,
2207
+ items: runtime.blockedTargets.map((cardId) => ({ label: cardId, value: "blocked" }))
2208
+ });
2209
+ if (runtime.blockedTargets.length > 0) {
2210
+ const mode = runtime.supportCandidates.length > 0 ? "direct-support" : runtime.discoveredSupportCandidates.length > 0 ? "inserted-support" : "boost-only";
2211
+ gauges.push({
2212
+ id: `group:${group.id}:support`,
2213
+ label: `${group.id} support`,
2214
+ multiplier: runtime.supportMultiplier,
2215
+ max: MAX_SUPPORT_MULTIPLIER,
2216
+ detail: `mode=${mode} \xB7 ${runtime.supportTags.length} support tag(s)`,
2217
+ items: runtime.supportTags.map((tag) => ({ label: tag }))
2218
+ });
2219
+ }
2220
+ const debts = practiceDebtsByGroup.get(group.id) ?? [];
2221
+ if (debts.length > 0) {
2222
+ gauges.push({
2223
+ id: `group:${group.id}:practice-debt`,
2224
+ label: `${group.id} practice debt`,
2225
+ multiplier: Math.max(...debts.map((d) => d.multiplier)),
2226
+ max: MAX_PRACTICE_MULTIPLIER,
2227
+ detail: `${debts.length} under-practiced skill(s)`,
2228
+ items: debts.map((d) => ({
2229
+ label: d.tag,
2230
+ value: `\xD7${d.multiplier.toFixed(2)} \xB7 open ${formatAge(now - new Date(d.firstOwedAt).getTime())}`
2231
+ }))
2232
+ });
2233
+ }
2234
+ }
2235
+ captureStrategyPressure({
2236
+ source: "prescribed",
2237
+ courseId,
2238
+ gauges,
2239
+ topScore: emitted.length > 0 ? Math.max(...emitted.map((c) => c.score)) : null,
2240
+ hintsLabel: hints?._label,
2241
+ timestamp: now
2242
+ });
2243
+ }
2155
2244
  parseConfig(serializedData) {
2156
2245
  try {
2157
2246
  const parsed = JSON.parse(serializedData);
@@ -2308,6 +2397,7 @@ var init_prescribed = __esm({
2308
2397
  supportTags: [...supportTags],
2309
2398
  pressureMultiplier,
2310
2399
  supportMultiplier,
2400
+ sessionsSinceSurfaced,
2311
2401
  debugVersion: PRESCRIBED_DEBUG_VERSION
2312
2402
  };
2313
2403
  }
@@ -2440,13 +2530,13 @@ var init_prescribed = __esm({
2440
2530
  nextPracticeDebt
2441
2531
  } = args;
2442
2532
  const patterns = group.practiceTagPatterns ?? [];
2443
- if (patterns.length === 0) return [];
2533
+ if (patterns.length === 0) return { cards: [], debts: [] };
2444
2534
  const practiceMinCount = group.practiceMinCount ?? DEFAULT_PRACTICE_MIN_COUNT;
2445
2535
  const maxPractice = group.maxPracticeCardsPerRun ?? DEFAULT_MAX_PRACTICE_PER_RUN;
2446
2536
  const practiceTags = [...cardsByTag.keys()].filter(
2447
2537
  (tag) => patterns.some((p) => matchesTagPattern(tag, p)) && this.isUnlockedGatedSkill(tag, hierarchyConfigs, userTagElo, userGlobalElo) && (userTagElo[tag]?.count ?? 0) < practiceMinCount
2448
2538
  );
2449
- if (practiceTags.length === 0) return [];
2539
+ if (practiceTags.length === 0) return { cards: [], debts: [] };
2450
2540
  const now = Date.now();
2451
2541
  const DAY_MS = 24 * 60 * 60 * 1e3;
2452
2542
  const tagMultiplier = /* @__PURE__ */ new Map();
@@ -2461,6 +2551,11 @@ var init_prescribed = __esm({
2461
2551
  );
2462
2552
  tagMultiplier.set(tag, mult);
2463
2553
  }
2554
+ const debts = practiceTags.map((tag) => ({
2555
+ tag,
2556
+ multiplier: tagMultiplier.get(tag) ?? PRACTICE_BASE_MULT,
2557
+ firstOwedAt: nextPracticeDebt[tag]
2558
+ })).sort((a, b) => b.multiplier - a.multiplier || a.tag.localeCompare(b.tag));
2464
2559
  const practiceCardIds = this.findDiscoveredSupportCards({
2465
2560
  supportTags: practiceTags,
2466
2561
  cardsByTag,
@@ -2469,7 +2564,7 @@ var init_prescribed = __esm({
2469
2564
  excludedIds: emittedIds,
2470
2565
  limit: maxPractice
2471
2566
  });
2472
- if (practiceCardIds.length === 0) return [];
2567
+ if (practiceCardIds.length === 0) return { cards: [], debts };
2473
2568
  logger.info(
2474
2569
  `[Prescribed] Group '${group.id}' practice: ${practiceTags.length} unlocked under-practiced skill(s), emitting ${practiceCardIds.length} drill card(s)`
2475
2570
  );
@@ -2499,7 +2594,7 @@ var init_prescribed = __esm({
2499
2594
  ]
2500
2595
  });
2501
2596
  }
2502
- return cards;
2597
+ return { cards, debts };
2503
2598
  }
2504
2599
  /**
2505
2600
  * True for a skill that was *gated and is now reached*: it has at least one
@@ -4930,6 +5025,7 @@ var init_3 = __esm({
4930
5025
  "./PipelineAssembler.ts": () => Promise.resolve().then(() => (init_PipelineAssembler(), PipelineAssembler_exports)),
4931
5026
  "./PipelineDebugger.ts": () => Promise.resolve().then(() => (init_PipelineDebugger(), PipelineDebugger_exports)),
4932
5027
  "./SrsDebugger.ts": () => Promise.resolve().then(() => (init_SrsDebugger(), SrsDebugger_exports)),
5028
+ "./StrategyPressureDebugger.ts": () => Promise.resolve().then(() => (init_StrategyPressureDebugger(), StrategyPressureDebugger_exports)),
4933
5029
  "./defaults.ts": () => Promise.resolve().then(() => (init_defaults(), defaults_exports)),
4934
5030
  "./diversityRerank.ts": () => Promise.resolve().then(() => (init_diversityRerank(), diversityRerank_exports)),
4935
5031
  "./filters/WeightedFilter.ts": () => Promise.resolve().then(() => (init_WeightedFilter(), WeightedFilter_exports)),
@@ -4962,7 +5058,9 @@ __export(navigators_exports, {
4962
5058
  NavigatorRole: () => NavigatorRole,
4963
5059
  NavigatorRoles: () => NavigatorRoles,
4964
5060
  Navigators: () => Navigators,
5061
+ captureStrategyPressure: () => captureStrategyPressure,
4965
5062
  clearSrsBacklogDebug: () => clearSrsBacklogDebug,
5063
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
4966
5064
  diversityRerank: () => diversityRerank,
4967
5065
  getActivePipeline: () => getActivePipeline,
4968
5066
  getCardOrigin: () => getCardOrigin,
@@ -4970,6 +5068,7 @@ __export(navigators_exports, {
4970
5068
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
4971
5069
  getRegisteredNavigatorRole: () => getRegisteredNavigatorRole,
4972
5070
  getSrsBacklogDebug: () => getSrsBacklogDebug,
5071
+ getStrategyPressureDebug: () => getStrategyPressureDebug,
4973
5072
  hasRegisteredNavigator: () => hasRegisteredNavigator,
4974
5073
  initializeNavigatorRegistry: () => initializeNavigatorRegistry,
4975
5074
  isFilter: () => isFilter,
@@ -5052,6 +5151,7 @@ var init_navigators = __esm({
5052
5151
  init_diversityRerank();
5053
5152
  init_PipelineDebugger();
5054
5153
  init_SrsDebugger();
5154
+ init_StrategyPressureDebugger();
5055
5155
  init_logger();
5056
5156
  init_();
5057
5157
  init_2();