@indigoai-us/hq-cloud 6.18.41-alpha.0 → 6.18.41-alpha.2

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.
@@ -21,7 +21,7 @@ import { PresignObjectIO, S3SdkObjectIO } from "../object-io.js";
21
21
  import { BandwidthGovernor, setBandwidthGovernorForTesting, } from "../bandwidth.js";
22
22
  import { POST_SYNC_FLAG_KEYS, } from "./sync-runner-post-sync-flags.js";
23
23
  import { FakeClock, TreeWatcher, createWatchPathFilter, } from "../watcher.js";
24
- import { adaptivePollMs, advanceMonotonicDeadline, DEFAULT_EVENT_BATCH_LIMIT, DEFAULT_FAST_LANE_MAX_BYTES, DEFAULT_FAST_LANE_MAX_FILE_BYTES, DEFAULT_FAST_LANE_MAX_FILES, DEFAULT_FULL_RECONCILE_MS, EVENT_BATCH_LIMIT_ENV, FAST_LANE_MAX_BYTES_ENV, FAST_LANE_MAX_FILES_ENV, FULL_RECONCILE_MS_ENV, isFastLocalBatch, isLargeLocalUpload, localUploadSizeClass, isChoreLocalPush, isSessionLogsPushOnlyPath, isFastReceiverBatch, partitionLocalBatch, journalEntriesForWatcherDelete, resolveEventBatchLimit, resolveFullReconcileMs, resolveWatchPollMs, CHORE_STARVATION_CAP_MS, CooperativePassScheduler, allowConcurrentHandoffForGuardedWork, REALTIME_ADMISSION_DEADLINE_MS, REALTIME_DRAIN_BURST_MS, REALTIME_WORKER_OCCUPANCY_CAP, REALTIME_LARGE_UPLOAD_THRESHOLD_BYTES, RealtimeAdmissionTimeoutError, setRealtimeAdmissionDeadlineMsForTesting, setRealtimeDrainBurstMsForTesting, normalizeCoordinatorPaths, shouldQuarantineWatcherDeleteIntents, shouldUseAreaStorage, WATCHER_REDISCOVERY_RETRY_MS, WATCHER_REDISCOVERY_RETRY_MAX_MS, EVENT_SYNC_STARTUP_SHUTDOWN_WAIT_MS, } from "./sync-runner-watch-loop.js";
24
+ import { adaptivePollMs, advanceMonotonicDeadline, DEFAULT_EVENT_BATCH_LIMIT, DEFAULT_FAST_LANE_MAX_BYTES, DEFAULT_FAST_LANE_MAX_FILE_BYTES, DEFAULT_FAST_LANE_MAX_FILES, DEFAULT_FULL_RECONCILE_MS, EVENT_BATCH_LIMIT_ENV, FAST_LANE_MAX_BYTES_ENV, FAST_LANE_MAX_FILES_ENV, FULL_RECONCILE_MS_ENV, isFastLocalBatch, isLargeLocalUpload, localUploadSizeClass, isChoreLocalPush, isSessionLogsPushOnlyPath, isFastReceiverBatch, partitionLocalBatch, journalEntriesForWatcherDelete, resolveEventBatchLimit, resolveFullReconcileMs, resolveWatchPollMs, CHORE_STARVATION_CAP_MS, CooperativePassScheduler, realtimeBlockerLabel, allowConcurrentHandoffForGuardedWork, REALTIME_ADMISSION_DEADLINE_MS, REALTIME_DRAIN_BURST_MS, REALTIME_WORKER_OCCUPANCY_CAP, REALTIME_LARGE_UPLOAD_THRESHOLD_BYTES, RealtimeAdmissionTimeoutError, setRealtimeAdmissionDeadlineMsForTesting, setRealtimeDrainBurstMsForTesting, normalizeCoordinatorPaths, shouldQuarantineWatcherDeleteIntents, shouldUseAreaStorage, WATCHER_REDISCOVERY_RETRY_MS, WATCHER_REDISCOVERY_RETRY_MAX_MS, EVENT_SYNC_STARTUP_SHUTDOWN_WAIT_MS, } from "./sync-runner-watch-loop.js";
25
25
  import { FullPassCapController, resetFullPassCapLogForTest, } from "../sync/full-pass-caps.js";
26
26
  import { AreaLedgerMigration, JournalStore, getJournalPath, openJournalStateStoreForMigration, PERSONAL_VAULT_JOURNAL_SLUG, readJournal, readJournalForPass, readJournalScoped, readJournalScopedAsync, writeJournal, } from "../journal.js";
27
27
  import { AreaLedger } from "../sync/area-ledger.js";
@@ -10381,6 +10381,86 @@ describe("runRunnerWithLoop — U58 realtime scheduler guard", () => {
10381
10381
  process.env.HQ_SYNC_PARALLEL_COORDINATOR = previousCoordinator;
10382
10382
  }
10383
10383
  });
10384
+ it("REGRESSION: a wake drain held behind a running chore names that chore", async () => {
10385
+ const previousCoordinator = process.env.HQ_SYNC_PARALLEL_COORDINATOR;
10386
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = "1";
10387
+ const watcher = makeWatcherStub();
10388
+ let triggerShutdown = () => { };
10389
+ let releaseCheckpoint = () => { };
10390
+ const checkpointGate = new Promise((resolve) => { releaseCheckpoint = resolve; });
10391
+ let markChoreHeld = () => { };
10392
+ const choreHeld = new Promise((resolve) => { markChoreHeld = resolve; });
10393
+ let passes = 0;
10394
+ let runRealtime = null;
10395
+ const timings = [];
10396
+ const stderr = vi.spyOn(process.stderr, "write").mockImplementation((chunk) => {
10397
+ if (typeof chunk === "string" && chunk.startsWith("{")) {
10398
+ try {
10399
+ const record = JSON.parse(chunk);
10400
+ if (record.event === "sync.realtime.timing")
10401
+ timings.push(record);
10402
+ }
10403
+ catch {
10404
+ // Non-telemetry diagnostics are outside this assertion.
10405
+ }
10406
+ }
10407
+ return true;
10408
+ });
10409
+ const loop = runRunnerWithLoop(["--companies", "--watch", "--event-push", "--hq-root", "/tmp/hq"], {
10410
+ runPass: vi.fn().mockImplementation(async (_argv, checkpoint) => {
10411
+ passes += 1;
10412
+ if (passes === 2) {
10413
+ markChoreHeld();
10414
+ await checkpointGate;
10415
+ await checkpoint?.();
10416
+ }
10417
+ return completedPassOutcome();
10418
+ }),
10419
+ runPassSupportsCooperativeCheckpoint: true,
10420
+ clock: new FakeClock(),
10421
+ createWatcher: () => watcher,
10422
+ sleep: makeSteppableSleep().sleep,
10423
+ onShutdownSignal: (handler) => {
10424
+ triggerShutdown = handler;
10425
+ return () => { };
10426
+ },
10427
+ startRealtimeScheduler: async (opts) => {
10428
+ runRealtime = () => opts.runGuarded(async () => undefined);
10429
+ return {
10430
+ signal: () => undefined,
10431
+ checkHighWater: async () => undefined,
10432
+ dispose: async () => undefined,
10433
+ };
10434
+ },
10435
+ });
10436
+ try {
10437
+ await flushLoopMicrotasks(30);
10438
+ watcher.emit();
10439
+ await choreHeld;
10440
+ await flushLoopMicrotasks(10);
10441
+ const wake = runRealtime();
10442
+ await flushLoopMicrotasks(20);
10443
+ releaseCheckpoint();
10444
+ await wake;
10445
+ await flushLoopMicrotasks(20);
10446
+ const wakeTimings = timings.filter((record) => record.source === "wake");
10447
+ expect(wakeTimings).toHaveLength(1);
10448
+ expect(wakeTimings[0]).toMatchObject({
10449
+ schemaVersion: 6,
10450
+ operationGateBlockedBy: "chore:full-reconcile",
10451
+ });
10452
+ }
10453
+ finally {
10454
+ releaseCheckpoint();
10455
+ triggerShutdown();
10456
+ await loop;
10457
+ stderr.mockRestore();
10458
+ if (previousCoordinator === undefined)
10459
+ delete process.env.HQ_SYNC_PARALLEL_COORDINATOR;
10460
+ else
10461
+ process.env.HQ_SYNC_PARALLEL_COORDINATOR = previousCoordinator;
10462
+ }
10463
+ });
10384
10464
  it("feeds a watcher-originated V2 drain through the same single-flight guard as the poll", async () => {
10385
10465
  const watcher = makeWatcherStub();
10386
10466
  let triggerShutdown = () => { };
@@ -11333,6 +11413,101 @@ describe("CooperativePassScheduler", () => {
11333
11413
  await scheduler.submit(async () => 0, "realtime", "slow", false, undefined, false, false, undefined, "unknown", (blocker) => heldBy.push(`${blocker.workClass}:${blocker.lane}`));
11334
11414
  expect(heldBy).toEqual(["chore:slow"]);
11335
11415
  });
11416
+ it("names the fast-lane occupant, not the slow pass, when a fast task queues behind it", async () => {
11417
+ const scheduler = new CooperativePassScheduler(() => 0);
11418
+ const heldBy = [];
11419
+ let releaseSlow = () => { };
11420
+ let releaseFast = () => { };
11421
+ const slowGate = new Promise((resolve) => { releaseSlow = resolve; });
11422
+ const fastGate = new Promise((resolve) => { releaseFast = resolve; });
11423
+ const slow = scheduler.submit(async () => { await slowGate; return 0; }, "realtime", "slow");
11424
+ await Promise.resolve();
11425
+ const fast = scheduler.submit(async () => { await fastGate; return 0; }, "realtime", "fast", true);
11426
+ await Promise.resolve();
11427
+ const queued = scheduler.submit(async () => 0, "realtime", "fast", true, undefined, false, false, undefined, "unknown", (blocker) => heldBy.push(blocker));
11428
+ expect(heldBy).toEqual([{ workClass: "realtime", lane: "fast" }]);
11429
+ releaseFast();
11430
+ releaseSlow();
11431
+ await Promise.all([slow, fast, queued]);
11432
+ });
11433
+ it("names the chore that holds the scheduler, not a later chore still waiting behind it", async () => {
11434
+ const scheduler = new CooperativePassScheduler(() => 0);
11435
+ const heldBy = [];
11436
+ let releaseFirst = () => { };
11437
+ const firstGate = new Promise((resolve) => { releaseFirst = resolve; });
11438
+ // A chore outside the coordinator owns the scheduler (no kind) ...
11439
+ const first = scheduler.submit(async ({ checkpoint }) => {
11440
+ await firstGate;
11441
+ await checkpoint();
11442
+ return 0;
11443
+ }, "chore");
11444
+ await Promise.resolve();
11445
+ // ... while a coordinator chore with a kind waits behind it.
11446
+ let releaseSecond = () => { };
11447
+ const secondGate = new Promise((resolve) => { releaseSecond = resolve; });
11448
+ let markSecondStarted = () => { };
11449
+ const secondStarted = new Promise((resolve) => { markSecondStarted = resolve; });
11450
+ const second = scheduler.submit(async ({ checkpoint }) => {
11451
+ markSecondStarted();
11452
+ await secondGate;
11453
+ await checkpoint();
11454
+ return 0;
11455
+ }, "chore", "slow", false, undefined, false, false, undefined, "unknown", undefined, "cadence");
11456
+ const realtime = scheduler.submit(async () => 0, "realtime", "slow", false, undefined, false, false, undefined, "unknown", (blocker) => heldBy.push(blocker));
11457
+ expect(heldBy).toEqual([{ workClass: "chore", lane: "slow" }]);
11458
+ releaseFirst();
11459
+ await first;
11460
+ await realtime;
11461
+ await secondStarted;
11462
+ // Now the kinded chore owns the scheduler; a new op is told its kind.
11463
+ const later = scheduler.submit(async () => 0, "realtime", "slow", false, undefined, false, false, undefined, "unknown", (blocker) => heldBy.push(blocker));
11464
+ expect(heldBy[1]).toEqual({ workClass: "chore", lane: "slow", choreKind: "cadence" });
11465
+ releaseSecond();
11466
+ await Promise.all([second, later]);
11467
+ });
11468
+ it("names the hand-off occupant that refuses admission, then the chore lending the slot", async () => {
11469
+ const scheduler = new CooperativePassScheduler(() => 0);
11470
+ const heldBy = [];
11471
+ let releaseCheckpoint = () => { };
11472
+ const checkpointGate = new Promise((resolve) => { releaseCheckpoint = resolve; });
11473
+ let releaseOccupant = () => { };
11474
+ const occupantGate = new Promise((resolve) => { releaseOccupant = resolve; });
11475
+ let markOccupantStarted = () => { };
11476
+ const occupantStarted = new Promise((resolve) => { markOccupantStarted = resolve; });
11477
+ const chore = scheduler.submit(async ({ checkpoint }) => {
11478
+ await checkpointGate;
11479
+ await checkpoint();
11480
+ return 0;
11481
+ }, "chore", "slow", false, undefined, true, false, undefined, "unknown", undefined, "full-reconcile");
11482
+ await Promise.resolve();
11483
+ // A coordinator-fenced push waits for the chore, then runs as a hand-off occupant.
11484
+ const occupant = scheduler.submit(async () => {
11485
+ markOccupantStarted();
11486
+ await occupantGate;
11487
+ return 0;
11488
+ }, "realtime", "slow", false, undefined, false, true, "push", "small");
11489
+ releaseCheckpoint();
11490
+ await occupantStarted;
11491
+ expect(scheduler.handoffActive).toBe(true);
11492
+ // A second push cannot share the occupant's direction, so the occupant holds it.
11493
+ const samePush = scheduler.submit(async () => 0, "realtime", "slow", false, undefined, false, true, "push", "small", (blocker) => heldBy.push(blocker));
11494
+ // A legacy (unfenced) op cannot join the hand-off at all; the lending chore holds it.
11495
+ const legacy = scheduler.submit(async () => 0, "realtime", "slow", false, undefined, false, false, undefined, "unknown", (blocker) => heldBy.push(blocker));
11496
+ expect(heldBy).toEqual([
11497
+ { workClass: "realtime", lane: "slow" },
11498
+ { workClass: "chore", lane: "slow", choreKind: "full-reconcile" },
11499
+ ]);
11500
+ releaseOccupant();
11501
+ await Promise.all([chore, occupant, samePush, legacy]);
11502
+ });
11503
+ it("labels an unknown chore kind as chore:unscoped instead of failing the timing record", () => {
11504
+ expect(realtimeBlockerLabel({ workClass: "chore", lane: "slow", choreKind: "full-reconcile" }))
11505
+ .toBe("chore:full-reconcile");
11506
+ expect(realtimeBlockerLabel({ workClass: "chore", lane: "slow", choreKind: "future-kind" }))
11507
+ .toBe("chore:unscoped");
11508
+ expect(realtimeBlockerLabel({ workClass: "chore", lane: "slow" })).toBe("chore:unscoped");
11509
+ expect(realtimeBlockerLabel({ workClass: "realtime", lane: "fast" })).toBe("realtime:fast");
11510
+ });
11336
11511
  it("refuses to wait past 2x the authorization timeout when the chore never yields", async () => {
11337
11512
  setRealtimeAdmissionDeadlineMsForTesting(40);
11338
11513
  const scheduler = new CooperativePassScheduler(() => 0);