@vue-skuilder/db 0.1.38 → 0.1.39

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/index.d.cts CHANGED
@@ -422,13 +422,6 @@ declare class SessionController<TView = unknown> extends Loggable {
422
422
  * Cleared when the depletion-triggered replan fires (newQ exhausted).
423
423
  */
424
424
  private _suppressQualityReplan;
425
- /**
426
- * Guards against infinite depletion-triggered replans. Set to true
427
- * when a depletion replan fires; cleared when a replan produces
428
- * content (newQ.length > 0 after replan) or when an explicit
429
- * (non-auto) replan is requested.
430
- */
431
- private _depletionReplanAttempted;
432
425
  /**
433
426
  * When > 0, the session timer cannot end the session. Decremented on
434
427
  * each nextCard() draw. Set by replans that include `minFollowUpCards`.
@@ -521,6 +514,19 @@ declare class SessionController<TView = unknown> extends Loggable {
521
514
  * newQ.peek(0) is the imminent draw we need to exclude.
522
515
  */
523
516
  private _runReplan;
517
+ /**
518
+ * Run a replan, bypassing requestReplan()'s coalesce logic.
519
+ *
520
+ * Use this when correctness depends on a *fresh* pipeline run, not on
521
+ * the existence of *some* in-flight replan. Specifically: the
522
+ * wedge-breaker path in nextCard(), where coalescing into a previous
523
+ * run that we now know produced insufficient content would re-create
524
+ * the bug we're trying to prevent.
525
+ *
526
+ * Still tracks _replanPromise like requestReplan() does so concurrent
527
+ * observers (auto-trigger guards in nextCard()) see consistent state.
528
+ */
529
+ private _replanUncoalesced;
524
530
  /**
525
531
  * Normalise the requestReplan argument. Accepts either a ReplanOptions
526
532
  * object (new API) or a plain Record<string, unknown> (legacy callers
package/dist/index.d.ts CHANGED
@@ -422,13 +422,6 @@ declare class SessionController<TView = unknown> extends Loggable {
422
422
  * Cleared when the depletion-triggered replan fires (newQ exhausted).
423
423
  */
424
424
  private _suppressQualityReplan;
425
- /**
426
- * Guards against infinite depletion-triggered replans. Set to true
427
- * when a depletion replan fires; cleared when a replan produces
428
- * content (newQ.length > 0 after replan) or when an explicit
429
- * (non-auto) replan is requested.
430
- */
431
- private _depletionReplanAttempted;
432
425
  /**
433
426
  * When > 0, the session timer cannot end the session. Decremented on
434
427
  * each nextCard() draw. Set by replans that include `minFollowUpCards`.
@@ -521,6 +514,19 @@ declare class SessionController<TView = unknown> extends Loggable {
521
514
  * newQ.peek(0) is the imminent draw we need to exclude.
522
515
  */
523
516
  private _runReplan;
517
+ /**
518
+ * Run a replan, bypassing requestReplan()'s coalesce logic.
519
+ *
520
+ * Use this when correctness depends on a *fresh* pipeline run, not on
521
+ * the existence of *some* in-flight replan. Specifically: the
522
+ * wedge-breaker path in nextCard(), where coalescing into a previous
523
+ * run that we now know produced insufficient content would re-create
524
+ * the bug we're trying to prevent.
525
+ *
526
+ * Still tracks _replanPromise like requestReplan() does so concurrent
527
+ * observers (auto-trigger guards in nextCard()) see consistent state.
528
+ */
529
+ private _replanUncoalesced;
524
530
  /**
525
531
  * Normalise the requestReplan argument. Accepts either a ReplanOptions
526
532
  * object (new API) or a plain Record<string, unknown> (legacy callers
package/dist/index.js CHANGED
@@ -13387,13 +13387,6 @@ var SessionController = class _SessionController extends Loggable {
13387
13387
  * Cleared when the depletion-triggered replan fires (newQ exhausted).
13388
13388
  */
13389
13389
  _suppressQualityReplan = false;
13390
- /**
13391
- * Guards against infinite depletion-triggered replans. Set to true
13392
- * when a depletion replan fires; cleared when a replan produces
13393
- * content (newQ.length > 0 after replan) or when an explicit
13394
- * (non-auto) replan is requested.
13395
- */
13396
- _depletionReplanAttempted = false;
13397
13390
  /**
13398
13391
  * When > 0, the session timer cannot end the session. Decremented on
13399
13392
  * each nextCard() draw. Set by replans that include `minFollowUpCards`.
@@ -13551,9 +13544,6 @@ var SessionController = class _SessionController extends Loggable {
13551
13544
  */
13552
13545
  async requestReplan(options) {
13553
13546
  const opts = this.normalizeReplanOptions(options);
13554
- if (opts.hints || opts.label || opts.limit) {
13555
- this._depletionReplanAttempted = false;
13556
- }
13557
13547
  const hasIntent = this._replanHasIntent(opts);
13558
13548
  if (this._replanPromise) {
13559
13549
  if (!hasIntent) {
@@ -13632,6 +13622,25 @@ var SessionController = class _SessionController extends Loggable {
13632
13622
  }
13633
13623
  await this._executeReplan(opts);
13634
13624
  }
13625
+ /**
13626
+ * Run a replan, bypassing requestReplan()'s coalesce logic.
13627
+ *
13628
+ * Use this when correctness depends on a *fresh* pipeline run, not on
13629
+ * the existence of *some* in-flight replan. Specifically: the
13630
+ * wedge-breaker path in nextCard(), where coalescing into a previous
13631
+ * run that we now know produced insufficient content would re-create
13632
+ * the bug we're trying to prevent.
13633
+ *
13634
+ * Still tracks _replanPromise like requestReplan() does so concurrent
13635
+ * observers (auto-trigger guards in nextCard()) see consistent state.
13636
+ */
13637
+ async _replanUncoalesced(opts) {
13638
+ const run = this._runReplan(opts);
13639
+ this._replanPromise = run.finally(() => {
13640
+ if (this._replanPromise === run) this._replanPromise = null;
13641
+ });
13642
+ await run;
13643
+ }
13635
13644
  /**
13636
13645
  * Normalise the requestReplan argument. Accepts either a ReplanOptions
13637
13646
  * object (new API) or a plain Record<string, unknown> (legacy callers
@@ -13685,9 +13694,6 @@ var SessionController = class _SessionController extends Loggable {
13685
13694
  `[Replan] Only ${wellIndicated}/${_SessionController.MIN_WELL_INDICATED} well-indicated cards after replan`
13686
13695
  );
13687
13696
  }
13688
- if (this.newQ.length > 0) {
13689
- this._depletionReplanAttempted = false;
13690
- }
13691
13697
  await this.hydrationService.ensureHydratedCards();
13692
13698
  const labelTag = opts.label ? ` [${opts.label}]` : "";
13693
13699
  this.log(`Replan complete${labelTag}: newQ now has ${this.newQ.length} cards (mode=${mode})`);
@@ -13966,21 +13972,13 @@ var SessionController = class _SessionController extends Loggable {
13966
13972
  this.log("nextCard: awaiting in-flight replan before drawing");
13967
13973
  await this._replanPromise;
13968
13974
  }
13969
- if (this.newQ.length <= 1 && this._secondsRemaining > 0 && !this._replanPromise && !this._depletionReplanAttempted) {
13975
+ if (this.newQ.length <= 1 && this._secondsRemaining > 0 && !this._replanPromise) {
13970
13976
  this._suppressQualityReplan = false;
13971
- this._depletionReplanAttempted = true;
13972
13977
  const otherContent = this.reviewQ.length + this.failedQ.length;
13973
- if (this.newQ.length === 0 && otherContent === 0) {
13974
- this.log(
13975
- `[AutoReplan:depletion] All queues empty with ${this._secondsRemaining}s remaining. Awaiting replan.`
13976
- );
13977
- await this.requestReplan();
13978
- } else {
13979
- this.log(
13980
- `[AutoReplan:depletion] newQ has ${this.newQ.length} card(s) (${otherContent} in other queues) with ${this._secondsRemaining}s remaining. Triggering background replan.`
13981
- );
13982
- void this.requestReplan();
13983
- }
13978
+ this.log(
13979
+ `[AutoReplan:depletion] newQ has ${this.newQ.length} card(s) (${otherContent} in other queues) with ${this._secondsRemaining}s remaining. Triggering background replan.`
13980
+ );
13981
+ void this.requestReplan();
13984
13982
  }
13985
13983
  const REPLAN_BUFFER = 3;
13986
13984
  if (!this._suppressQualityReplan && this._wellIndicatedRemaining <= REPLAN_BUFFER && this.newQ.length > 0 && !this._replanPromise) {
@@ -13994,6 +13992,27 @@ var SessionController = class _SessionController extends Loggable {
13994
13992
  endSessionTracking();
13995
13993
  return null;
13996
13994
  }
13995
+ const WEDGE_MAX_EMPTY_STREAK = 3;
13996
+ const WEDGE_BACKOFF_MS = 250;
13997
+ let wedgeEmptyStreak = 0;
13998
+ while (this._secondsRemaining > 0 && this.newQ.length === 0 && this.reviewQ.length === 0 && this.failedQ.length === 0) {
13999
+ this.log(
14000
+ `[WedgeBreaker] All queues empty with ${this._secondsRemaining}s remaining. Running pipeline (attempt ${wedgeEmptyStreak + 1}/${WEDGE_MAX_EMPTY_STREAK}).`
14001
+ );
14002
+ await this._replanUncoalesced({ label: "wedge-breaker" });
14003
+ if (this.newQ.length === 0 && this.reviewQ.length === 0 && this.failedQ.length === 0) {
14004
+ wedgeEmptyStreak++;
14005
+ if (wedgeEmptyStreak >= WEDGE_MAX_EMPTY_STREAK) {
14006
+ this.log(
14007
+ `[WedgeBreaker] Pipeline returned no content ${WEDGE_MAX_EMPTY_STREAK} consecutive times. Giving up; session will end.`
14008
+ );
14009
+ break;
14010
+ }
14011
+ await new Promise((resolve) => setTimeout(resolve, WEDGE_BACKOFF_MS));
14012
+ } else {
14013
+ wedgeEmptyStreak = 0;
14014
+ }
14015
+ }
13997
14016
  const MAX_SKIP = 20;
13998
14017
  for (let attempt = 0; attempt < MAX_SKIP; attempt++) {
13999
14018
  const nextItem = this._selectNextItemToHydrate();