@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.
@@ -1470,6 +1470,30 @@ var init_SrsDebugger = __esm({
1470
1470
  }
1471
1471
  });
1472
1472
 
1473
+ // src/core/navigators/StrategyPressureDebugger.ts
1474
+ var StrategyPressureDebugger_exports = {};
1475
+ __export(StrategyPressureDebugger_exports, {
1476
+ captureStrategyPressure: () => captureStrategyPressure,
1477
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
1478
+ getStrategyPressureDebug: () => getStrategyPressureDebug
1479
+ });
1480
+ function captureStrategyPressure(snapshot) {
1481
+ snapshots2.set(`${snapshot.source}:${snapshot.courseId}`, snapshot);
1482
+ }
1483
+ function getStrategyPressureDebug() {
1484
+ return [...snapshots2.values()].sort((a, b) => b.timestamp - a.timestamp);
1485
+ }
1486
+ function clearStrategyPressureDebug() {
1487
+ snapshots2.clear();
1488
+ }
1489
+ var snapshots2;
1490
+ var init_StrategyPressureDebugger = __esm({
1491
+ "src/core/navigators/StrategyPressureDebugger.ts"() {
1492
+ "use strict";
1493
+ snapshots2 = /* @__PURE__ */ new Map();
1494
+ }
1495
+ });
1496
+
1473
1497
  // src/core/navigators/generators/CompositeGenerator.ts
1474
1498
  var CompositeGenerator_exports = {};
1475
1499
  __export(CompositeGenerator_exports, {
@@ -1834,6 +1858,13 @@ function shuffleInPlace(arr) {
1834
1858
  [arr[i], arr[j]] = [arr[j], arr[i]];
1835
1859
  }
1836
1860
  }
1861
+ function formatAge(ms) {
1862
+ const minutes = Math.max(0, Math.round(ms / 6e4));
1863
+ if (minutes < 60) return `${minutes}m`;
1864
+ const hours = Math.round(minutes / 60);
1865
+ if (hours < 24) return `${hours}h`;
1866
+ return `${Math.round(hours / 24)}d`;
1867
+ }
1837
1868
  function pickTopByScore(cards, limit) {
1838
1869
  return [...cards].sort((a, b) => b.score - a.score || a.cardId.localeCompare(b.cardId)).slice(0, limit);
1839
1870
  }
@@ -1842,6 +1873,7 @@ var init_prescribed = __esm({
1842
1873
  "src/core/navigators/generators/prescribed.ts"() {
1843
1874
  "use strict";
1844
1875
  init_navigators();
1876
+ init_StrategyPressureDebugger();
1845
1877
  init_logger();
1846
1878
  DEFAULT_FRESHNESS_WINDOW = 3;
1847
1879
  DEFAULT_MAX_DIRECT_PER_RUN = 3;
@@ -1918,6 +1950,7 @@ var init_prescribed = __esm({
1918
1950
  const groupRuntimes = [];
1919
1951
  const priorPracticeDebt = progress.practiceDebt ?? {};
1920
1952
  const nextPracticeDebt = {};
1953
+ const practiceDebtsByGroup = /* @__PURE__ */ new Map();
1921
1954
  for (const group of this.config.groups) {
1922
1955
  const runtime = this.buildGroupRuntimeState({
1923
1956
  group,
@@ -1966,7 +1999,7 @@ var init_prescribed = __esm({
1966
1999
  courseId,
1967
2000
  emittedIds
1968
2001
  );
1969
- const practiceCards = this.buildPracticeCards({
2002
+ const practice = this.buildPracticeCards({
1970
2003
  group,
1971
2004
  courseId,
1972
2005
  emittedIds,
@@ -1979,7 +2012,8 @@ var init_prescribed = __esm({
1979
2012
  priorPracticeDebt,
1980
2013
  nextPracticeDebt
1981
2014
  });
1982
- emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practiceCards);
2015
+ practiceDebtsByGroup.set(group.id, practice.debts);
2016
+ emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practice.cards);
1983
2017
  }
1984
2018
  nextState.practiceDebt = nextPracticeDebt;
1985
2019
  const hintSummary = this.buildSupportHintSummary(groupRuntimes);
@@ -1995,6 +2029,7 @@ var init_prescribed = __esm({
1995
2029
  } else {
1996
2030
  logger.info("[Prescribed] No hints to emit (no blocked targets or no support tags)");
1997
2031
  }
2032
+ this.capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints);
1998
2033
  if (emitted.length === 0) {
1999
2034
  logger.info(
2000
2035
  "[Prescribed] 0 cards emitted (all targets blocked, authored/discovered support candidates exhausted)" + (hints ? " \u2014 boost hints emitted but may not survive filters" : "")
@@ -2056,6 +2091,60 @@ var init_prescribed = __esm({
2056
2091
  supportTags: [...supportTags].sort()
2057
2092
  };
2058
2093
  }
2094
+ /**
2095
+ * Translate this run's per-group runtimes and practice debts into gauges on
2096
+ * the generic strategy-pressure debug channel (rendered by the live session
2097
+ * overlay's "strategy backpressure" section).
2098
+ */
2099
+ capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints) {
2100
+ const now = Date.now();
2101
+ const gauges = [];
2102
+ for (const runtime of groupRuntimes) {
2103
+ const group = runtime.group;
2104
+ const window2 = group.freshnessWindowSessions ?? DEFAULT_FRESHNESS_WINDOW;
2105
+ gauges.push({
2106
+ id: `group:${group.id}:target`,
2107
+ label: `${group.id} targets`,
2108
+ multiplier: runtime.pressureMultiplier,
2109
+ max: MAX_TARGET_MULTIPLIER,
2110
+ detail: `${runtime.pendingTargets.length} pending (${runtime.surfaceableTargets.length} surfaceable, ${runtime.blockedTargets.length} blocked) \xB7 sinceSurfaced ${runtime.sessionsSinceSurfaced}/${window2}`,
2111
+ items: runtime.blockedTargets.map((cardId) => ({ label: cardId, value: "blocked" }))
2112
+ });
2113
+ if (runtime.blockedTargets.length > 0) {
2114
+ const mode = runtime.supportCandidates.length > 0 ? "direct-support" : runtime.discoveredSupportCandidates.length > 0 ? "inserted-support" : "boost-only";
2115
+ gauges.push({
2116
+ id: `group:${group.id}:support`,
2117
+ label: `${group.id} support`,
2118
+ multiplier: runtime.supportMultiplier,
2119
+ max: MAX_SUPPORT_MULTIPLIER,
2120
+ detail: `mode=${mode} \xB7 ${runtime.supportTags.length} support tag(s)`,
2121
+ items: runtime.supportTags.map((tag) => ({ label: tag }))
2122
+ });
2123
+ }
2124
+ const debts = practiceDebtsByGroup.get(group.id) ?? [];
2125
+ if (debts.length > 0) {
2126
+ gauges.push({
2127
+ id: `group:${group.id}:practice-debt`,
2128
+ label: `${group.id} practice debt`,
2129
+ multiplier: Math.max(...debts.map((d) => d.multiplier)),
2130
+ max: MAX_PRACTICE_MULTIPLIER,
2131
+ detail: `${debts.length} under-practiced skill(s)`,
2132
+ items: debts.map((d) => ({
2133
+ label: d.tag,
2134
+ value: `\xD7${d.multiplier.toFixed(2)} \xB7 open ${formatAge(now - new Date(d.firstOwedAt).getTime())}`
2135
+ }))
2136
+ });
2137
+ }
2138
+ }
2139
+ captureStrategyPressure({
2140
+ source: "prescribed",
2141
+ courseId,
2142
+ gauges,
2143
+ topScore: emitted.length > 0 ? Math.max(...emitted.map((c) => c.score)) : null,
2144
+ hintsLabel: hints?._label,
2145
+ timestamp: now
2146
+ });
2147
+ }
2059
2148
  parseConfig(serializedData) {
2060
2149
  try {
2061
2150
  const parsed = JSON.parse(serializedData);
@@ -2212,6 +2301,7 @@ var init_prescribed = __esm({
2212
2301
  supportTags: [...supportTags],
2213
2302
  pressureMultiplier,
2214
2303
  supportMultiplier,
2304
+ sessionsSinceSurfaced,
2215
2305
  debugVersion: PRESCRIBED_DEBUG_VERSION
2216
2306
  };
2217
2307
  }
@@ -2344,13 +2434,13 @@ var init_prescribed = __esm({
2344
2434
  nextPracticeDebt
2345
2435
  } = args;
2346
2436
  const patterns = group.practiceTagPatterns ?? [];
2347
- if (patterns.length === 0) return [];
2437
+ if (patterns.length === 0) return { cards: [], debts: [] };
2348
2438
  const practiceMinCount = group.practiceMinCount ?? DEFAULT_PRACTICE_MIN_COUNT;
2349
2439
  const maxPractice = group.maxPracticeCardsPerRun ?? DEFAULT_MAX_PRACTICE_PER_RUN;
2350
2440
  const practiceTags = [...cardsByTag.keys()].filter(
2351
2441
  (tag) => patterns.some((p) => matchesTagPattern(tag, p)) && this.isUnlockedGatedSkill(tag, hierarchyConfigs, userTagElo, userGlobalElo) && (userTagElo[tag]?.count ?? 0) < practiceMinCount
2352
2442
  );
2353
- if (practiceTags.length === 0) return [];
2443
+ if (practiceTags.length === 0) return { cards: [], debts: [] };
2354
2444
  const now = Date.now();
2355
2445
  const DAY_MS = 24 * 60 * 60 * 1e3;
2356
2446
  const tagMultiplier = /* @__PURE__ */ new Map();
@@ -2365,6 +2455,11 @@ var init_prescribed = __esm({
2365
2455
  );
2366
2456
  tagMultiplier.set(tag, mult);
2367
2457
  }
2458
+ const debts = practiceTags.map((tag) => ({
2459
+ tag,
2460
+ multiplier: tagMultiplier.get(tag) ?? PRACTICE_BASE_MULT,
2461
+ firstOwedAt: nextPracticeDebt[tag]
2462
+ })).sort((a, b) => b.multiplier - a.multiplier || a.tag.localeCompare(b.tag));
2368
2463
  const practiceCardIds = this.findDiscoveredSupportCards({
2369
2464
  supportTags: practiceTags,
2370
2465
  cardsByTag,
@@ -2373,7 +2468,7 @@ var init_prescribed = __esm({
2373
2468
  excludedIds: emittedIds,
2374
2469
  limit: maxPractice
2375
2470
  });
2376
- if (practiceCardIds.length === 0) return [];
2471
+ if (practiceCardIds.length === 0) return { cards: [], debts };
2377
2472
  logger.info(
2378
2473
  `[Prescribed] Group '${group.id}' practice: ${practiceTags.length} unlocked under-practiced skill(s), emitting ${practiceCardIds.length} drill card(s)`
2379
2474
  );
@@ -2403,7 +2498,7 @@ var init_prescribed = __esm({
2403
2498
  ]
2404
2499
  });
2405
2500
  }
2406
- return cards;
2501
+ return { cards, debts };
2407
2502
  }
2408
2503
  /**
2409
2504
  * True for a skill that was *gated and is now reached*: it has at least one
@@ -4834,6 +4929,7 @@ var init_3 = __esm({
4834
4929
  "./PipelineAssembler.ts": () => Promise.resolve().then(() => (init_PipelineAssembler(), PipelineAssembler_exports)),
4835
4930
  "./PipelineDebugger.ts": () => Promise.resolve().then(() => (init_PipelineDebugger(), PipelineDebugger_exports)),
4836
4931
  "./SrsDebugger.ts": () => Promise.resolve().then(() => (init_SrsDebugger(), SrsDebugger_exports)),
4932
+ "./StrategyPressureDebugger.ts": () => Promise.resolve().then(() => (init_StrategyPressureDebugger(), StrategyPressureDebugger_exports)),
4837
4933
  "./defaults.ts": () => Promise.resolve().then(() => (init_defaults(), defaults_exports)),
4838
4934
  "./diversityRerank.ts": () => Promise.resolve().then(() => (init_diversityRerank(), diversityRerank_exports)),
4839
4935
  "./filters/WeightedFilter.ts": () => Promise.resolve().then(() => (init_WeightedFilter(), WeightedFilter_exports)),
@@ -4866,7 +4962,9 @@ __export(navigators_exports, {
4866
4962
  NavigatorRole: () => NavigatorRole,
4867
4963
  NavigatorRoles: () => NavigatorRoles,
4868
4964
  Navigators: () => Navigators,
4965
+ captureStrategyPressure: () => captureStrategyPressure,
4869
4966
  clearSrsBacklogDebug: () => clearSrsBacklogDebug,
4967
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
4870
4968
  diversityRerank: () => diversityRerank,
4871
4969
  getActivePipeline: () => getActivePipeline,
4872
4970
  getCardOrigin: () => getCardOrigin,
@@ -4874,6 +4972,7 @@ __export(navigators_exports, {
4874
4972
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
4875
4973
  getRegisteredNavigatorRole: () => getRegisteredNavigatorRole,
4876
4974
  getSrsBacklogDebug: () => getSrsBacklogDebug,
4975
+ getStrategyPressureDebug: () => getStrategyPressureDebug,
4877
4976
  hasRegisteredNavigator: () => hasRegisteredNavigator,
4878
4977
  initializeNavigatorRegistry: () => initializeNavigatorRegistry,
4879
4978
  isFilter: () => isFilter,
@@ -4956,6 +5055,7 @@ var init_navigators = __esm({
4956
5055
  init_diversityRerank();
4957
5056
  init_PipelineDebugger();
4958
5057
  init_SrsDebugger();
5058
+ init_StrategyPressureDebugger();
4959
5059
  init_logger();
4960
5060
  init_();
4961
5061
  init_2();