@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.
@@ -1446,6 +1446,30 @@ var init_SrsDebugger = __esm({
1446
1446
  }
1447
1447
  });
1448
1448
 
1449
+ // src/core/navigators/StrategyPressureDebugger.ts
1450
+ var StrategyPressureDebugger_exports = {};
1451
+ __export(StrategyPressureDebugger_exports, {
1452
+ captureStrategyPressure: () => captureStrategyPressure,
1453
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
1454
+ getStrategyPressureDebug: () => getStrategyPressureDebug
1455
+ });
1456
+ function captureStrategyPressure(snapshot) {
1457
+ snapshots2.set(`${snapshot.source}:${snapshot.courseId}`, snapshot);
1458
+ }
1459
+ function getStrategyPressureDebug() {
1460
+ return [...snapshots2.values()].sort((a, b) => b.timestamp - a.timestamp);
1461
+ }
1462
+ function clearStrategyPressureDebug() {
1463
+ snapshots2.clear();
1464
+ }
1465
+ var snapshots2;
1466
+ var init_StrategyPressureDebugger = __esm({
1467
+ "src/core/navigators/StrategyPressureDebugger.ts"() {
1468
+ "use strict";
1469
+ snapshots2 = /* @__PURE__ */ new Map();
1470
+ }
1471
+ });
1472
+
1449
1473
  // src/core/navigators/generators/CompositeGenerator.ts
1450
1474
  var CompositeGenerator_exports = {};
1451
1475
  __export(CompositeGenerator_exports, {
@@ -1810,6 +1834,13 @@ function shuffleInPlace(arr) {
1810
1834
  [arr[i], arr[j]] = [arr[j], arr[i]];
1811
1835
  }
1812
1836
  }
1837
+ function formatAge(ms) {
1838
+ const minutes = Math.max(0, Math.round(ms / 6e4));
1839
+ if (minutes < 60) return `${minutes}m`;
1840
+ const hours = Math.round(minutes / 60);
1841
+ if (hours < 24) return `${hours}h`;
1842
+ return `${Math.round(hours / 24)}d`;
1843
+ }
1813
1844
  function pickTopByScore(cards, limit) {
1814
1845
  return [...cards].sort((a, b) => b.score - a.score || a.cardId.localeCompare(b.cardId)).slice(0, limit);
1815
1846
  }
@@ -1818,6 +1849,7 @@ var init_prescribed = __esm({
1818
1849
  "src/core/navigators/generators/prescribed.ts"() {
1819
1850
  "use strict";
1820
1851
  init_navigators();
1852
+ init_StrategyPressureDebugger();
1821
1853
  init_logger();
1822
1854
  DEFAULT_FRESHNESS_WINDOW = 3;
1823
1855
  DEFAULT_MAX_DIRECT_PER_RUN = 3;
@@ -1894,6 +1926,7 @@ var init_prescribed = __esm({
1894
1926
  const groupRuntimes = [];
1895
1927
  const priorPracticeDebt = progress.practiceDebt ?? {};
1896
1928
  const nextPracticeDebt = {};
1929
+ const practiceDebtsByGroup = /* @__PURE__ */ new Map();
1897
1930
  for (const group of this.config.groups) {
1898
1931
  const runtime = this.buildGroupRuntimeState({
1899
1932
  group,
@@ -1942,7 +1975,7 @@ var init_prescribed = __esm({
1942
1975
  courseId,
1943
1976
  emittedIds
1944
1977
  );
1945
- const practiceCards = this.buildPracticeCards({
1978
+ const practice = this.buildPracticeCards({
1946
1979
  group,
1947
1980
  courseId,
1948
1981
  emittedIds,
@@ -1955,7 +1988,8 @@ var init_prescribed = __esm({
1955
1988
  priorPracticeDebt,
1956
1989
  nextPracticeDebt
1957
1990
  });
1958
- emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practiceCards);
1991
+ practiceDebtsByGroup.set(group.id, practice.debts);
1992
+ emitted.push(...directCards, ...supportCards, ...discoveredSupportCards, ...practice.cards);
1959
1993
  }
1960
1994
  nextState.practiceDebt = nextPracticeDebt;
1961
1995
  const hintSummary = this.buildSupportHintSummary(groupRuntimes);
@@ -1971,6 +2005,7 @@ var init_prescribed = __esm({
1971
2005
  } else {
1972
2006
  logger.info("[Prescribed] No hints to emit (no blocked targets or no support tags)");
1973
2007
  }
2008
+ this.capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints);
1974
2009
  if (emitted.length === 0) {
1975
2010
  logger.info(
1976
2011
  "[Prescribed] 0 cards emitted (all targets blocked, authored/discovered support candidates exhausted)" + (hints ? " \u2014 boost hints emitted but may not survive filters" : "")
@@ -2032,6 +2067,60 @@ var init_prescribed = __esm({
2032
2067
  supportTags: [...supportTags].sort()
2033
2068
  };
2034
2069
  }
2070
+ /**
2071
+ * Translate this run's per-group runtimes and practice debts into gauges on
2072
+ * the generic strategy-pressure debug channel (rendered by the live session
2073
+ * overlay's "strategy backpressure" section).
2074
+ */
2075
+ capturePressureSnapshot(courseId, groupRuntimes, practiceDebtsByGroup, emitted, hints) {
2076
+ const now = Date.now();
2077
+ const gauges = [];
2078
+ for (const runtime of groupRuntimes) {
2079
+ const group = runtime.group;
2080
+ const window2 = group.freshnessWindowSessions ?? DEFAULT_FRESHNESS_WINDOW;
2081
+ gauges.push({
2082
+ id: `group:${group.id}:target`,
2083
+ label: `${group.id} targets`,
2084
+ multiplier: runtime.pressureMultiplier,
2085
+ max: MAX_TARGET_MULTIPLIER,
2086
+ detail: `${runtime.pendingTargets.length} pending (${runtime.surfaceableTargets.length} surfaceable, ${runtime.blockedTargets.length} blocked) \xB7 sinceSurfaced ${runtime.sessionsSinceSurfaced}/${window2}`,
2087
+ items: runtime.blockedTargets.map((cardId) => ({ label: cardId, value: "blocked" }))
2088
+ });
2089
+ if (runtime.blockedTargets.length > 0) {
2090
+ const mode = runtime.supportCandidates.length > 0 ? "direct-support" : runtime.discoveredSupportCandidates.length > 0 ? "inserted-support" : "boost-only";
2091
+ gauges.push({
2092
+ id: `group:${group.id}:support`,
2093
+ label: `${group.id} support`,
2094
+ multiplier: runtime.supportMultiplier,
2095
+ max: MAX_SUPPORT_MULTIPLIER,
2096
+ detail: `mode=${mode} \xB7 ${runtime.supportTags.length} support tag(s)`,
2097
+ items: runtime.supportTags.map((tag) => ({ label: tag }))
2098
+ });
2099
+ }
2100
+ const debts = practiceDebtsByGroup.get(group.id) ?? [];
2101
+ if (debts.length > 0) {
2102
+ gauges.push({
2103
+ id: `group:${group.id}:practice-debt`,
2104
+ label: `${group.id} practice debt`,
2105
+ multiplier: Math.max(...debts.map((d) => d.multiplier)),
2106
+ max: MAX_PRACTICE_MULTIPLIER,
2107
+ detail: `${debts.length} under-practiced skill(s)`,
2108
+ items: debts.map((d) => ({
2109
+ label: d.tag,
2110
+ value: `\xD7${d.multiplier.toFixed(2)} \xB7 open ${formatAge(now - new Date(d.firstOwedAt).getTime())}`
2111
+ }))
2112
+ });
2113
+ }
2114
+ }
2115
+ captureStrategyPressure({
2116
+ source: "prescribed",
2117
+ courseId,
2118
+ gauges,
2119
+ topScore: emitted.length > 0 ? Math.max(...emitted.map((c) => c.score)) : null,
2120
+ hintsLabel: hints?._label,
2121
+ timestamp: now
2122
+ });
2123
+ }
2035
2124
  parseConfig(serializedData) {
2036
2125
  try {
2037
2126
  const parsed = JSON.parse(serializedData);
@@ -2188,6 +2277,7 @@ var init_prescribed = __esm({
2188
2277
  supportTags: [...supportTags],
2189
2278
  pressureMultiplier,
2190
2279
  supportMultiplier,
2280
+ sessionsSinceSurfaced,
2191
2281
  debugVersion: PRESCRIBED_DEBUG_VERSION
2192
2282
  };
2193
2283
  }
@@ -2320,13 +2410,13 @@ var init_prescribed = __esm({
2320
2410
  nextPracticeDebt
2321
2411
  } = args;
2322
2412
  const patterns = group.practiceTagPatterns ?? [];
2323
- if (patterns.length === 0) return [];
2413
+ if (patterns.length === 0) return { cards: [], debts: [] };
2324
2414
  const practiceMinCount = group.practiceMinCount ?? DEFAULT_PRACTICE_MIN_COUNT;
2325
2415
  const maxPractice = group.maxPracticeCardsPerRun ?? DEFAULT_MAX_PRACTICE_PER_RUN;
2326
2416
  const practiceTags = [...cardsByTag.keys()].filter(
2327
2417
  (tag) => patterns.some((p) => matchesTagPattern(tag, p)) && this.isUnlockedGatedSkill(tag, hierarchyConfigs, userTagElo, userGlobalElo) && (userTagElo[tag]?.count ?? 0) < practiceMinCount
2328
2418
  );
2329
- if (practiceTags.length === 0) return [];
2419
+ if (practiceTags.length === 0) return { cards: [], debts: [] };
2330
2420
  const now = Date.now();
2331
2421
  const DAY_MS = 24 * 60 * 60 * 1e3;
2332
2422
  const tagMultiplier = /* @__PURE__ */ new Map();
@@ -2341,6 +2431,11 @@ var init_prescribed = __esm({
2341
2431
  );
2342
2432
  tagMultiplier.set(tag, mult);
2343
2433
  }
2434
+ const debts = practiceTags.map((tag) => ({
2435
+ tag,
2436
+ multiplier: tagMultiplier.get(tag) ?? PRACTICE_BASE_MULT,
2437
+ firstOwedAt: nextPracticeDebt[tag]
2438
+ })).sort((a, b) => b.multiplier - a.multiplier || a.tag.localeCompare(b.tag));
2344
2439
  const practiceCardIds = this.findDiscoveredSupportCards({
2345
2440
  supportTags: practiceTags,
2346
2441
  cardsByTag,
@@ -2349,7 +2444,7 @@ var init_prescribed = __esm({
2349
2444
  excludedIds: emittedIds,
2350
2445
  limit: maxPractice
2351
2446
  });
2352
- if (practiceCardIds.length === 0) return [];
2447
+ if (practiceCardIds.length === 0) return { cards: [], debts };
2353
2448
  logger.info(
2354
2449
  `[Prescribed] Group '${group.id}' practice: ${practiceTags.length} unlocked under-practiced skill(s), emitting ${practiceCardIds.length} drill card(s)`
2355
2450
  );
@@ -2379,7 +2474,7 @@ var init_prescribed = __esm({
2379
2474
  ]
2380
2475
  });
2381
2476
  }
2382
- return cards;
2477
+ return { cards, debts };
2383
2478
  }
2384
2479
  /**
2385
2480
  * True for a skill that was *gated and is now reached*: it has at least one
@@ -4810,6 +4905,7 @@ var init_3 = __esm({
4810
4905
  "./PipelineAssembler.ts": () => Promise.resolve().then(() => (init_PipelineAssembler(), PipelineAssembler_exports)),
4811
4906
  "./PipelineDebugger.ts": () => Promise.resolve().then(() => (init_PipelineDebugger(), PipelineDebugger_exports)),
4812
4907
  "./SrsDebugger.ts": () => Promise.resolve().then(() => (init_SrsDebugger(), SrsDebugger_exports)),
4908
+ "./StrategyPressureDebugger.ts": () => Promise.resolve().then(() => (init_StrategyPressureDebugger(), StrategyPressureDebugger_exports)),
4813
4909
  "./defaults.ts": () => Promise.resolve().then(() => (init_defaults(), defaults_exports)),
4814
4910
  "./diversityRerank.ts": () => Promise.resolve().then(() => (init_diversityRerank(), diversityRerank_exports)),
4815
4911
  "./filters/WeightedFilter.ts": () => Promise.resolve().then(() => (init_WeightedFilter(), WeightedFilter_exports)),
@@ -4842,7 +4938,9 @@ __export(navigators_exports, {
4842
4938
  NavigatorRole: () => NavigatorRole,
4843
4939
  NavigatorRoles: () => NavigatorRoles,
4844
4940
  Navigators: () => Navigators,
4941
+ captureStrategyPressure: () => captureStrategyPressure,
4845
4942
  clearSrsBacklogDebug: () => clearSrsBacklogDebug,
4943
+ clearStrategyPressureDebug: () => clearStrategyPressureDebug,
4846
4944
  diversityRerank: () => diversityRerank,
4847
4945
  getActivePipeline: () => getActivePipeline,
4848
4946
  getCardOrigin: () => getCardOrigin,
@@ -4850,6 +4948,7 @@ __export(navigators_exports, {
4850
4948
  getRegisteredNavigatorNames: () => getRegisteredNavigatorNames,
4851
4949
  getRegisteredNavigatorRole: () => getRegisteredNavigatorRole,
4852
4950
  getSrsBacklogDebug: () => getSrsBacklogDebug,
4951
+ getStrategyPressureDebug: () => getStrategyPressureDebug,
4853
4952
  hasRegisteredNavigator: () => hasRegisteredNavigator,
4854
4953
  initializeNavigatorRegistry: () => initializeNavigatorRegistry,
4855
4954
  isFilter: () => isFilter,
@@ -4932,6 +5031,7 @@ var init_navigators = __esm({
4932
5031
  init_diversityRerank();
4933
5032
  init_PipelineDebugger();
4934
5033
  init_SrsDebugger();
5034
+ init_StrategyPressureDebugger();
4935
5035
  init_logger();
4936
5036
  init_();
4937
5037
  init_2();